diff options
181 files changed, 4001 insertions, 1935 deletions
diff --git a/apct-tests/perftests/core/Android.bp b/apct-tests/perftests/core/Android.bp index ab20fdbde1e5..98e4f4509b52 100644 --- a/apct-tests/perftests/core/Android.bp +++ b/apct-tests/perftests/core/Android.bp @@ -44,6 +44,8 @@ android_test { "apct-perftests-utils", "collector-device-lib", "compatibility-device-util-axt", + "junit", + "junit-params", "core-tests-support", "guava", ], diff --git a/apct-tests/perftests/core/src/android/libcore/DeepArrayOpsPerfTest.java b/apct-tests/perftests/core/src/android/libcore/DeepArrayOpsPerfTest.java index 3f4f6af7554c..3ebaa4cd0bfa 100644 --- a/apct-tests/perftests/core/src/android/libcore/DeepArrayOpsPerfTest.java +++ b/apct-tests/perftests/core/src/android/libcore/DeepArrayOpsPerfTest.java @@ -20,18 +20,19 @@ import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; import android.test.suitebuilder.annotation.LargeTest; -import org.junit.Before; +import junitparams.JUnitParamsRunner; +import junitparams.Parameters; + import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; import java.lang.reflect.Array; import java.lang.reflect.Constructor; import java.util.Arrays; import java.util.Collection; -@RunWith(Parameterized.class) +@RunWith(JUnitParamsRunner.class) @LargeTest public class DeepArrayOpsPerfTest { @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter(); @@ -39,19 +40,14 @@ public class DeepArrayOpsPerfTest { private Object[] mArray; private Object[] mArray2; - @Parameterized.Parameter(0) - public int mArrayLength; - - @Parameterized.Parameters(name = "mArrayLength({0})") - public static Collection<Object[]> data() { + public static Collection<Object[]> getData() { return Arrays.asList(new Object[][] {{1}, {4}, {16}, {32}, {2048}}); } - @Before - public void setUp() throws Exception { - mArray = new Object[mArrayLength * 14]; - mArray2 = new Object[mArrayLength * 14]; - for (int i = 0; i < mArrayLength; i += 14) { + public void setUp(int arrayLength) throws Exception { + mArray = new Object[arrayLength * 14]; + mArray2 = new Object[arrayLength * 14]; + for (int i = 0; i < arrayLength; i += 14) { mArray[i] = new IntWrapper(i); mArray2[i] = new IntWrapper(i); @@ -99,7 +95,9 @@ public class DeepArrayOpsPerfTest { } @Test - public void deepHashCode() { + @Parameters(method = "getData") + public void deepHashCode(int arrayLength) throws Exception { + setUp(arrayLength); BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { Arrays.deepHashCode(mArray); @@ -107,7 +105,9 @@ public class DeepArrayOpsPerfTest { } @Test - public void deepEquals() { + @Parameters(method = "getData") + public void deepEquals(int arrayLength) throws Exception { + setUp(arrayLength); BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { Arrays.deepEquals(mArray, mArray2); diff --git a/apct-tests/perftests/core/src/android/libcore/SystemArrayCopyPerfTest.java b/apct-tests/perftests/core/src/android/libcore/SystemArrayCopyPerfTest.java index 5aacfc25bfd1..20f1309bd8e6 100644 --- a/apct-tests/perftests/core/src/android/libcore/SystemArrayCopyPerfTest.java +++ b/apct-tests/perftests/core/src/android/libcore/SystemArrayCopyPerfTest.java @@ -20,22 +20,22 @@ import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; import android.test.suitebuilder.annotation.LargeTest; +import junitparams.JUnitParamsRunner; +import junitparams.Parameters; + import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; import java.util.Arrays; import java.util.Collection; -@RunWith(Parameterized.class) +@RunWith(JUnitParamsRunner.class) @LargeTest public class SystemArrayCopyPerfTest { @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter(); - @Parameters(name = "arrayLength={0}") - public static Collection<Object[]> data() { + public static Collection<Object[]> getData() { return Arrays.asList( new Object[][] { {2}, {4}, {8}, {16}, {32}, {64}, {128}, {256}, {512}, {1024}, {2048}, {4096}, @@ -43,12 +43,10 @@ public class SystemArrayCopyPerfTest { }); } - @Parameterized.Parameter(0) - public int arrayLength; - // Provides benchmarking for different types of arrays using the arraycopy function. @Test - public void timeSystemCharArrayCopy() { + @Parameters(method = "getData") + public void timeSystemCharArrayCopy(int arrayLength) { final int len = arrayLength; char[] src = new char[len]; char[] dst = new char[len]; @@ -59,7 +57,8 @@ public class SystemArrayCopyPerfTest { } @Test - public void timeSystemByteArrayCopy() { + @Parameters(method = "getData") + public void timeSystemByteArrayCopy(int arrayLength) { final int len = arrayLength; byte[] src = new byte[len]; byte[] dst = new byte[len]; @@ -70,7 +69,8 @@ public class SystemArrayCopyPerfTest { } @Test - public void timeSystemShortArrayCopy() { + @Parameters(method = "getData") + public void timeSystemShortArrayCopy(int arrayLength) { final int len = arrayLength; short[] src = new short[len]; short[] dst = new short[len]; @@ -81,7 +81,8 @@ public class SystemArrayCopyPerfTest { } @Test - public void timeSystemIntArrayCopy() { + @Parameters(method = "getData") + public void timeSystemIntArrayCopy(int arrayLength) { final int len = arrayLength; int[] src = new int[len]; int[] dst = new int[len]; @@ -92,7 +93,8 @@ public class SystemArrayCopyPerfTest { } @Test - public void timeSystemLongArrayCopy() { + @Parameters(method = "getData") + public void timeSystemLongArrayCopy(int arrayLength) { final int len = arrayLength; long[] src = new long[len]; long[] dst = new long[len]; @@ -103,7 +105,8 @@ public class SystemArrayCopyPerfTest { } @Test - public void timeSystemFloatArrayCopy() { + @Parameters(method = "getData") + public void timeSystemFloatArrayCopy(int arrayLength) { final int len = arrayLength; float[] src = new float[len]; float[] dst = new float[len]; @@ -114,7 +117,8 @@ public class SystemArrayCopyPerfTest { } @Test - public void timeSystemDoubleArrayCopy() { + @Parameters(method = "getData") + public void timeSystemDoubleArrayCopy(int arrayLength) { final int len = arrayLength; double[] src = new double[len]; double[] dst = new double[len]; @@ -125,7 +129,8 @@ public class SystemArrayCopyPerfTest { } @Test - public void timeSystemBooleanArrayCopy() { + @Parameters(method = "getData") + public void timeSystemBooleanArrayCopy(int arrayLength) { final int len = arrayLength; boolean[] src = new boolean[len]; boolean[] dst = new boolean[len]; diff --git a/apct-tests/perftests/core/src/android/libcore/XmlSerializePerfTest.java b/apct-tests/perftests/core/src/android/libcore/XmlSerializePerfTest.java index eec0734cffda..b1b594d64324 100644 --- a/apct-tests/perftests/core/src/android/libcore/XmlSerializePerfTest.java +++ b/apct-tests/perftests/core/src/android/libcore/XmlSerializePerfTest.java @@ -20,42 +20,32 @@ import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; import android.test.suitebuilder.annotation.LargeTest; -import org.junit.Before; +import junitparams.JUnitParamsRunner; +import junitparams.Parameters; + import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; import org.xmlpull.v1.XmlSerializer; import java.io.CharArrayWriter; import java.lang.reflect.Constructor; -import java.util.Arrays; -import java.util.Collection; import java.util.Random; -@RunWith(Parameterized.class) +@RunWith(JUnitParamsRunner.class) @LargeTest public class XmlSerializePerfTest { @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter(); - @Parameters(name = "mDatasetAsString({0}), mSeed({1})") - public static Collection<Object[]> data() { - return Arrays.asList( - new Object[][] { - {"0.99 0.7 0.7 0.7 0.7 0.7", 854328}, - {"0.999 0.3 0.3 0.95 0.9 0.9", 854328}, - {"0.99 0.7 0.7 0.7 0.7 0.7", 312547}, - {"0.999 0.3 0.3 0.95 0.9 0.9", 312547} - }); + private Object[] getParams() { + return new Object[][] { + new Object[] {"0.99 0.7 0.7 0.7 0.7 0.7", 854328}, + new Object[] {"0.999 0.3 0.3 0.95 0.9 0.9", 854328}, + new Object[] {"0.99 0.7 0.7 0.7 0.7 0.7", 312547}, + new Object[] {"0.999 0.3 0.3 0.95 0.9 0.9", 312547} + }; } - @Parameterized.Parameter(0) - public String mDatasetAsString; - - @Parameterized.Parameter(1) - public int mSeed; - double[] mDataset; private Constructor<? extends XmlSerializer> mKxmlConstructor; private Constructor<? extends XmlSerializer> mFastConstructor; @@ -100,8 +90,7 @@ public class XmlSerializePerfTest { } @SuppressWarnings("unchecked") - @Before - public void setUp() throws Exception { + public void setUp(String datasetAsString) throws Exception { mKxmlConstructor = (Constructor) Class.forName("com.android.org.kxml2.io.KXmlSerializer").getConstructor(); @@ -109,28 +98,32 @@ public class XmlSerializePerfTest { (Constructor) Class.forName("com.android.internal.util.FastXmlSerializer") .getConstructor(); - String[] splitStrings = mDatasetAsString.split(" "); + String[] splitStrings = datasetAsString.split(" "); mDataset = new double[splitStrings.length]; for (int i = 0; i < splitStrings.length; i++) { mDataset[i] = Double.parseDouble(splitStrings[i]); } } - private void internalTimeSerializer(Constructor<? extends XmlSerializer> ctor) + private void internalTimeSerializer(Constructor<? extends XmlSerializer> ctor, int seed) throws Exception { BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { - serializeRandomXml(ctor, mSeed); + serializeRandomXml(ctor, seed); } } @Test - public void timeKxml() throws Exception { - internalTimeSerializer(mKxmlConstructor); + @Parameters(method = "getParams") + public void timeKxml(String datasetAsString, int seed) throws Exception { + setUp(datasetAsString); + internalTimeSerializer(mKxmlConstructor, seed); } @Test - public void timeFast() throws Exception { - internalTimeSerializer(mFastConstructor); + @Parameters(method = "getParams") + public void timeFast(String datasetAsString, int seed) throws Exception { + setUp(datasetAsString); + internalTimeSerializer(mFastConstructor, seed); } } diff --git a/apct-tests/perftests/core/src/android/libcore/ZipFilePerfTest.java b/apct-tests/perftests/core/src/android/libcore/ZipFilePerfTest.java index 31c92ba5e207..3a45d4045d62 100644 --- a/apct-tests/perftests/core/src/android/libcore/ZipFilePerfTest.java +++ b/apct-tests/perftests/core/src/android/libcore/ZipFilePerfTest.java @@ -20,12 +20,12 @@ import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; import android.test.suitebuilder.annotation.LargeTest; -import org.junit.Before; +import junitparams.JUnitParamsRunner; +import junitparams.Parameters; + import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; import java.io.File; import java.io.FileOutputStream; @@ -38,23 +38,18 @@ import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import java.util.zip.ZipOutputStream; -@RunWith(Parameterized.class) +@RunWith(JUnitParamsRunner.class) @LargeTest public class ZipFilePerfTest { @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter(); private File mFile; - @Parameters(name = "numEntries={0}") - public static Collection<Object[]> data() { + public static Collection<Object[]> getData() { return Arrays.asList(new Object[][] {{128}, {1024}, {8192}}); } - @Parameterized.Parameter(0) - public int numEntries; - - @Before - public void setUp() throws Exception { + public void setUp(int numEntries) throws Exception { mFile = File.createTempFile(getClass().getName(), ".zip"); mFile.deleteOnExit(); writeEntries(new ZipOutputStream(new FileOutputStream(mFile)), numEntries, 0); @@ -66,7 +61,9 @@ public class ZipFilePerfTest { } @Test - public void timeZipFileOpen() throws Exception { + @Parameters(method = "getData") + public void timeZipFileOpen(int numEntries) throws Exception { + setUp(numEntries); BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { ZipFile zf = new ZipFile(mFile); diff --git a/apct-tests/perftests/core/src/android/libcore/ZipFileReadPerfTest.java b/apct-tests/perftests/core/src/android/libcore/ZipFileReadPerfTest.java index faa96285cefd..2e89518ec9fb 100644 --- a/apct-tests/perftests/core/src/android/libcore/ZipFileReadPerfTest.java +++ b/apct-tests/perftests/core/src/android/libcore/ZipFileReadPerfTest.java @@ -20,12 +20,13 @@ import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; import android.test.suitebuilder.annotation.LargeTest; +import junitparams.JUnitParamsRunner; +import junitparams.Parameters; + import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; import java.io.File; import java.io.FileOutputStream; @@ -39,21 +40,17 @@ import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import java.util.zip.ZipOutputStream; -@RunWith(Parameterized.class) +@RunWith(JUnitParamsRunner.class) @LargeTest public class ZipFileReadPerfTest { @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter(); - @Parameters(name = "readBufferSize={0}") - public static Collection<Object[]> data() { + public static Collection<Object[]> getData() { return Arrays.asList(new Object[][] {{1024}, {16384}, {65536}}); } private File mFile; - @Parameterized.Parameter(0) - public int readBufferSize; - @Before public void setUp() throws Exception { mFile = File.createTempFile(getClass().getName(), ".zip"); @@ -90,7 +87,8 @@ public class ZipFileReadPerfTest { } @Test - public void timeZipFileRead() throws Exception { + @Parameters(method = "getData") + public void timeZipFileRead(int readBufferSize) throws Exception { byte[] readBuffer = new byte[readBufferSize]; BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { 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 db5462cd69bf..2c0473eda830 100644 --- a/apct-tests/perftests/core/src/android/libcore/regression/BitSetPerfTest.java +++ b/apct-tests/perftests/core/src/android/libcore/regression/BitSetPerfTest.java @@ -20,96 +20,99 @@ import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; import android.test.suitebuilder.annotation.LargeTest; -import org.junit.Before; +import junitparams.JUnitParamsRunner; +import junitparams.Parameters; + import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; import java.util.Arrays; import java.util.BitSet; import java.util.Collection; -@RunWith(Parameterized.class) +@RunWith(JUnitParamsRunner.class) @LargeTest public class BitSetPerfTest { @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter(); - @Parameters(name = "mSize={0}") - public static Collection<Object[]> data() { + public static Collection<Object[]> getData() { return Arrays.asList(new Object[][] {{1000}, {10000}}); } - @Parameterized.Parameter(0) - public int mSize; - - private BitSet mBitSet; - - @Before - public void setUp() throws Exception { - mBitSet = new BitSet(mSize); - } - @Test - public void timeIsEmptyTrue() { + @Parameters(method = "getData") + public void timeIsEmptyTrue(int size) { + BitSet bitSet = new BitSet(size); BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { - if (!mBitSet.isEmpty()) throw new RuntimeException(); + if (!bitSet.isEmpty()) throw new RuntimeException(); } } @Test - public void timeIsEmptyFalse() { - mBitSet.set(mBitSet.size() - 1); + @Parameters(method = "getData") + public void timeIsEmptyFalse(int size) { + BitSet bitSet = new BitSet(size); + bitSet.set(bitSet.size() - 1); BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { - if (mBitSet.isEmpty()) throw new RuntimeException(); + if (bitSet.isEmpty()) throw new RuntimeException(); } } @Test - public void timeGet() { + @Parameters(method = "getData") + public void timeGet(int size) { + BitSet bitSet = new BitSet(size); BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); int i = 1; while (state.keepRunning()) { - mBitSet.get(++i % mSize); + bitSet.get(++i % size); } } @Test - public void timeClear() { + @Parameters(method = "getData") + public void timeClear(int size) { + BitSet bitSet = new BitSet(size); BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); int i = 1; while (state.keepRunning()) { - mBitSet.clear(++i % mSize); + bitSet.clear(++i % size); } } @Test - public void timeSet() { + @Parameters(method = "getData") + public void timeSet(int size) { + BitSet bitSet = new BitSet(size); int i = 1; BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { - mBitSet.set(++i % mSize); + bitSet.set(++i % size); } } @Test - public void timeSetOn() { + @Parameters(method = "getData") + public void timeSetOn(int size) { + BitSet bitSet = new BitSet(size); int i = 1; BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { - mBitSet.set(++i % mSize, true); + bitSet.set(++i % size, true); } } @Test - public void timeSetOff() { + @Parameters(method = "getData") + public void timeSetOff(int size) { + BitSet bitSet = new BitSet(size); int i = 1; BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { - mBitSet.set(++i % mSize, false); + 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 3952c12b3bfe..6a2ce5847daa 100644 --- a/apct-tests/perftests/core/src/android/libcore/regression/BreakIteratorPerfTest.java +++ b/apct-tests/perftests/core/src/android/libcore/regression/BreakIteratorPerfTest.java @@ -20,18 +20,19 @@ import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; import android.test.suitebuilder.annotation.LargeTest; +import junitparams.JUnitParamsRunner; +import junitparams.Parameters; + import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; import java.text.BreakIterator; import java.util.Arrays; import java.util.Collection; import java.util.Locale; -@RunWith(Parameterized.class) +@RunWith(JUnitParamsRunner.class) @LargeTest public final class BreakIteratorPerfTest { @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter(); @@ -41,36 +42,37 @@ public final class BreakIteratorPerfTest { Locale.US, "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi mollis consequat" + " nisl non pharetra. Praesent pretium vehicula odio sed ultrices. Aenean a" - + " felis libero. Vivamus sed commodo nibh. Pellentesque turpis lectus, euismod" - + " vel ante nec, cursus posuere orci. Suspendisse velit neque, fermentum" - + " luctus ultrices in, ultrices vitae arcu. Duis tincidunt cursus lorem. Nam" - + " ultricies accumsan quam vitae imperdiet. Pellentesque habitant morbi" - + " tristique senectus et netus et malesuada fames ac turpis egestas. Quisque" - + " aliquet pretium nisi, eget laoreet enim molestie sit amet. Class aptent" - + " taciti sociosqu ad litora torquent per conubia nostra, per inceptos" + + " felis libero. Vivamus sed commodo nibh. Pellentesque turpis lectus," + + " euismod vel ante nec, cursus posuere orci. Suspendisse velit neque," + + " fermentum luctus ultrices in, ultrices vitae arcu. Duis tincidunt cursus" + + " lorem. Nam ultricies accumsan quam vitae imperdiet. Pellentesque habitant" + + " morbi tristique senectus et netus et malesuada fames ac turpis egestas." + + " Quisque aliquet pretium nisi, eget laoreet enim molestie sit amet. Class" + + " aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos" + " himenaeos.\n" + "Nam dapibus aliquam lacus ac suscipit. Proin in nibh sit amet purus congue" + " laoreet eget quis nisl. Morbi gravida dignissim justo, a venenatis ante" - + " pulvinar at. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin" - + " ultrices vestibulum dui, vel aliquam lacus aliquam quis. Duis fringilla" - + " sapien ac lacus egestas, vel adipiscing elit euismod. Donec non tellus" - + " odio. Donec gravida eu massa ac feugiat. Aliquam erat volutpat. Praesent id" - + " adipiscing metus, nec laoreet enim. Aliquam vitae posuere turpis. Mauris ac" - + " pharetra sem. In at placerat tortor. Vivamus ac vehicula neque. Cras" - + " volutpat ullamcorper massa et varius. Praesent sagittis neque vitae nulla" - + " euismod pharetra.\n" + + " pulvinar at. Lorem ipsum dolor sit amet, consectetur adipiscing elit." + + " Proin ultrices vestibulum dui, vel aliquam lacus aliquam quis. Duis" + + " fringilla sapien ac lacus egestas, vel adipiscing elit euismod. Donec non" + + " tellus odio. Donec gravida eu massa ac feugiat. Aliquam erat volutpat." + + " Praesent id adipiscing metus, nec laoreet enim. Aliquam vitae posuere" + + " turpis. Mauris ac pharetra sem. In at placerat tortor. Vivamus ac vehicula" + + " neque. Cras volutpat ullamcorper massa et varius. Praesent sagittis neque" + + " vitae nulla euismod pharetra.\n" + "Sed placerat sapien non molestie sollicitudin. Nullam sit amet dictum quam." + " Etiam tincidunt tortor vel pretium vehicula. Praesent fringilla ipsum vel" + " velit luctus dignissim. Nulla massa ligula, mattis in enim et, mattis" + " lacinia odio. Suspendisse tristique urna a orci commodo tempor. Duis" + " lacinia egestas arcu a sollicitudin.\n" + "In ac feugiat lacus. Nunc fermentum eu est at tristique. Pellentesque quis" - + " ligula et orci placerat lacinia. Maecenas quis mauris diam. Etiam mi ipsum," - + " tempus in purus quis, euismod faucibus orci. Nulla facilisi. Praesent sit" - + " amet sapien vel elit porta adipiscing. Phasellus sit amet volutpat diam.\n" - + "Proin bibendum elit non lacus pharetra, quis eleifend tellus placerat. Nulla" - + " facilisi. Maecenas ante diam, pellentesque mattis mattis in, porta ut" - + " lorem. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices" + + " ligula et orci placerat lacinia. Maecenas quis mauris diam. Etiam mi" + + " ipsum, tempus in purus quis, euismod faucibus orci. Nulla facilisi." + + " Praesent sit amet sapien vel elit porta adipiscing. Phasellus sit amet" + + " volutpat diam.\n" + + "Proin bibendum elit non lacus pharetra, quis eleifend tellus placerat." + + " Nulla facilisi. Maecenas ante diam, pellentesque mattis mattis in, porta" + + " ut lorem. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices" + " posuere cubilia Curae; Nunc interdum tristique metus, in scelerisque odio" + " fermentum eget. Cras nec venenatis lacus. Aenean euismod eget metus quis" + " molestie. Cras tincidunt dolor ut massa ornare, in elementum lacus auctor." @@ -80,29 +82,29 @@ public final class BreakIteratorPerfTest { LONGPARA( Locale.US, "During dinner, Mr. Bennet scarcely spoke at all; but when the servants were" - + " withdrawn, he thought it time to have some conversation with his guest, and" - + " therefore started a subject in which he expected him to shine, by observing" - + " that he seemed very fortunate in his patroness. Lady Catherine de Bourgh's" - + " attention to his wishes, and consideration for his comfort, appeared very" - + " remarkable. Mr. Bennet could not have chosen better. Mr. Collins was" - + " eloquent in her praise. The subject elevated him to more than usual" - + " solemnity of manner, and with a most important aspect he protested that" - + " \"he had never in his life witnessed such behaviour in a person of" - + " rank--such affability and condescension, as he had himself experienced from" - + " Lady Catherine. She had been graciously pleased to approve of both of the" - + " discourses which he had already had the honour of preaching before her. She" - + " had also asked him twice to dine at Rosings, and had sent for him only the" - + " Saturday before, to make up her pool of quadrille in the evening. Lady" - + " Catherine was reckoned proud by many people he knew, but _he_ had never" - + " seen anything but affability in her. She had always spoken to him as she" - + " would to any other gentleman; she made not the smallest objection to his" - + " joining in the society of the neighbourhood nor to his leaving the parish" - + " occasionally for a week or two, to visit his relations. She had even" - + " condescended to advise him to marry as soon as he could, provided he chose" - + " with discretion; and had once paid him a visit in his humble parsonage," - + " where she had perfectly approved all the alterations he had been making," - + " and had even vouchsafed to suggest some herself--some shelves in the closet" - + " up stairs.\""), + + " withdrawn, he thought it time to have some conversation with his guest," + + " and therefore started a subject in which he expected him to shine, by" + + " observing that he seemed very fortunate in his patroness. Lady Catherine" + + " de Bourgh's attention to his wishes, and consideration for his comfort," + + " appeared very remarkable. Mr. Bennet could not have chosen better. Mr." + + " Collins was eloquent in her praise. The subject elevated him to more than" + + " usual solemnity of manner, and with a most important aspect he protested" + + " that \"he had never in his life witnessed such behaviour in a person of" + + " rank--such affability and condescension, as he had himself experienced" + + " from Lady Catherine. She had been graciously pleased to approve of both of" + + " the discourses which he had already had the honour of preaching before" + + " her. She had also asked him twice to dine at Rosings, and had sent for him" + + " only the Saturday before, to make up her pool of quadrille in the evening." + + " Lady Catherine was reckoned proud by many people he knew, but _he_ had" + + " never seen anything but affability in her. She had always spoken to him as" + + " she would to any other gentleman; she made not the smallest objection to" + + " his joining in the society of the neighbourhood nor to his leaving the" + + " parish occasionally for a week or two, to visit his relations. She had" + + " even condescended to advise him to marry as soon as he could, provided he" + + " chose with discretion; and had once paid him a visit in his humble" + + " parsonage, where she had perfectly approved all the alterations he had" + + " been making, and had even vouchsafed to suggest some herself--some shelves" + + " in the closet up stairs.\""), GERMAN( Locale.GERMANY, "Aber dieser Freiheit setzte endlich der Winter ein Ziel. Draußen auf den Feldern" @@ -119,15 +121,14 @@ public final class BreakIteratorPerfTest { + " เดิมทีเป็นการผสมผสานกันระหว่างสำเนียงอยุธยาและชาวไทยเชื้อสายจีนรุ่นหลังที่" + "พูดไทยแทนกลุ่มภาษาจีน" + " ลักษณะเด่นคือมีการออกเสียงที่ชัดเจนและแข็งกระด้างซึ่งได้รับอิทธิพลจากภาษาแต" - + "้จิ๋ว" - + " การออกเสียงพยัญชนะ สระ การผันวรรณยุกต์ที่ในภาษาไทยมาตรฐาน" + + "้จิ๋ว การออกเสียงพยัญชนะ สระ การผันวรรณยุกต์ที่ในภาษาไทยมาตรฐาน" + " มาจากสำเนียงถิ่นนี้ในขณะที่ภาษาไทยสำเนียงอื่นล้วนเหน่อทั้งสิ้น" + " คำศัพท์ที่ใช้ในสำเนียงกรุงเทพจำนวนมากได้รับมาจากกลุ่มภาษาจีนเช่นคำว่า โป๊," + " เฮ็ง, อาหมวย, อาซิ่ม ซึ่งมาจากภาษาแต้จิ๋ว และจากภาษาจีนเช่น ถู(涂), ชิ่ว(去" + " อ่านว่า\"ชู่\") และคำว่า ทาย(猜 อ่านว่า \"ชาย\") เป็นต้น" + " เนื่องจากสำเนียงกรุงเทพได้รับอิทธิพลมาจากภาษาจีนดังนั้นตัวอักษร \"ร\"" - + " มักออกเสียงเหมารวมเป็น \"ล\" หรือคำควบกล่ำบางคำถูกละทิ้งไปด้วยเช่น รู้ เป็น" - + " ลู้, เรื่อง เป็น เลื่อง หรือ ประเทศ เป็น ปะเทศ" + + " มักออกเสียงเหมารวมเป็น \"ล\" หรือคำควบกล่ำบางคำถูกละทิ้งไปด้วยเช่น รู้" + + " เป็น ลู้, เรื่อง เป็น เลื่อง หรือ ประเทศ เป็น ปะเทศ" + " เป็นต้นสร้างความลำบากให้แก่ต่างชาติที่ต้องการเรียนภาษาไทย" + " แต่อย่างไรก็ตามผู้ที่พูดสำเนียงถิ่นนี้ก็สามารถออกอักขระภาษาไทยตามมาตรฐานได" + "้อย่างถูกต้องเพียงแต่มักเผลอไม่ค่อยออกเสียง"), @@ -151,8 +152,7 @@ public final class BreakIteratorPerfTest { } } - @Parameters(name = "mText={0}") - public static Collection<Object[]> data() { + public static Collection<Object[]> getData() { return Arrays.asList( new Object[][] { {Text.ACCENT}, {Text.BIDI}, {Text.EMOJI}, {Text.EMPTY}, {Text.GERMAN}, @@ -161,15 +161,13 @@ public final class BreakIteratorPerfTest { }); } - @Parameterized.Parameter(0) - public Text mText; - @Test - public void timeBreakIterator() { + @Parameters(method = "getData") + public void timeBreakIterator(Text text) { BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { - BreakIterator it = BreakIterator.getLineInstance(mText.mLocale); - it.setText(mText.mText); + BreakIterator it = BreakIterator.getLineInstance(text.mLocale); + it.setText(text.mText); while (it.next() != BreakIterator.DONE) { // Keep iterating @@ -178,12 +176,13 @@ public final class BreakIteratorPerfTest { } @Test - public void timeIcuBreakIterator() { + @Parameters(method = "getData") + public void timeIcuBreakIterator(Text text) { BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { android.icu.text.BreakIterator it = - android.icu.text.BreakIterator.getLineInstance(mText.mLocale); - it.setText(mText.mText); + android.icu.text.BreakIterator.getLineInstance(text.mLocale); + it.setText(text.mText); while (it.next() != android.icu.text.BreakIterator.DONE) { // Keep iterating 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 855bb9a43d34..b7b7e83f147c 100644 --- a/apct-tests/perftests/core/src/android/libcore/regression/BulkPerfTest.java +++ b/apct-tests/perftests/core/src/android/libcore/regression/BulkPerfTest.java @@ -20,11 +20,12 @@ import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; import android.test.suitebuilder.annotation.LargeTest; +import junitparams.JUnitParamsRunner; +import junitparams.Parameters; + import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; import java.io.File; import java.io.IOException; @@ -34,13 +35,12 @@ import java.nio.channels.FileChannel; import java.util.Arrays; import java.util.Collection; -@RunWith(Parameterized.class) +@RunWith(JUnitParamsRunner.class) @LargeTest public class BulkPerfTest { @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter(); - @Parameters(name = "mAlign({0}), mSBuf({1}), mDBuf({2}), mSize({3})") - public static Collection<Object[]> data() { + public static Collection<Object[]> getData() { return Arrays.asList( new Object[][] { {true, MyBufferType.DIRECT, MyBufferType.DIRECT, 4096}, @@ -82,24 +82,12 @@ public class BulkPerfTest { }); } - @Parameterized.Parameter(0) - public boolean mAlign; - enum MyBufferType { DIRECT, HEAP, MAPPED } - @Parameterized.Parameter(1) - public MyBufferType mSBuf; - - @Parameterized.Parameter(2) - public MyBufferType mDBuf; - - @Parameterized.Parameter(3) - public int mSize; - public static ByteBuffer newBuffer(boolean aligned, MyBufferType bufferType, int bsize) throws IOException { int size = aligned ? bsize : bsize + 8 + 1; @@ -126,13 +114,15 @@ public class BulkPerfTest { } @Test - public void timePut() throws Exception { - ByteBuffer src = BulkPerfTest.newBuffer(mAlign, mSBuf, mSize); - ByteBuffer data = BulkPerfTest.newBuffer(mAlign, mDBuf, mSize); + @Parameters(method = "getData") + public void timePut(boolean align, MyBufferType sBuf, MyBufferType dBuf, int size) + throws Exception { + ByteBuffer src = BulkPerfTest.newBuffer(align, sBuf, size); + ByteBuffer data = BulkPerfTest.newBuffer(align, dBuf, size); BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { - src.position(mAlign ? 0 : 1); - data.position(mAlign ? 0 : 1); + src.position(align ? 0 : 1); + data.position(align ? 0 : 1); src.put(data); } } 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 4bd7c4e4fa82..9ac36d076c7b 100644 --- a/apct-tests/perftests/core/src/android/libcore/regression/ByteBufferPerfTest.java +++ b/apct-tests/perftests/core/src/android/libcore/regression/ByteBufferPerfTest.java @@ -20,11 +20,12 @@ import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; import android.test.suitebuilder.annotation.LargeTest; +import junitparams.JUnitParamsRunner; +import junitparams.Parameters; + import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; import java.io.File; import java.io.IOException; @@ -41,7 +42,7 @@ import java.nio.channels.FileChannel; import java.util.Arrays; import java.util.Collection; -@RunWith(Parameterized.class) +@RunWith(JUnitParamsRunner.class) @LargeTest public class ByteBufferPerfTest { @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter(); @@ -49,15 +50,14 @@ public class ByteBufferPerfTest { public enum MyByteOrder { BIG(ByteOrder.BIG_ENDIAN), LITTLE(ByteOrder.LITTLE_ENDIAN); - final ByteOrder mByteOrder; + final ByteOrder byteOrder; - MyByteOrder(ByteOrder mByteOrder) { - this.mByteOrder = mByteOrder; + MyByteOrder(ByteOrder byteOrder) { + this.byteOrder = byteOrder; } } - @Parameters(name = "mByteOrder={0}, mAligned={1}, mBufferType={2}") - public static Collection<Object[]> data() { + public static Collection<Object[]> getData() { return Arrays.asList( new Object[][] { {MyByteOrder.BIG, true, MyBufferType.DIRECT}, @@ -75,21 +75,12 @@ public class ByteBufferPerfTest { }); } - @Parameterized.Parameter(0) - public MyByteOrder mByteOrder; - - @Parameterized.Parameter(1) - public boolean mAligned; - enum MyBufferType { DIRECT, HEAP, MAPPED; } - @Parameterized.Parameter(2) - public MyBufferType mBufferType; - public static ByteBuffer newBuffer( MyByteOrder byteOrder, boolean aligned, MyBufferType bufferType) throws IOException { int size = aligned ? 8192 : 8192 + 8 + 1; @@ -115,7 +106,7 @@ public class ByteBufferPerfTest { result = fc.map(FileChannel.MapMode.READ_WRITE, 0, fc.size()); break; } - result.order(byteOrder.mByteOrder); + result.order(byteOrder.byteOrder); result.position(aligned ? 0 : 1); return result; } @@ -125,11 +116,13 @@ public class ByteBufferPerfTest { // @Test - public void timeByteBuffer_getByte() throws Exception { - ByteBuffer src = ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType); + @Parameters(method = "getData") + public void timeByteBuffer_getByte( + MyByteOrder byteOrder, boolean aligned, MyBufferType bufferType) throws Exception { + ByteBuffer src = ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType); BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { - src.position(mAligned ? 0 : 1); + src.position(aligned ? 0 : 1); for (int i = 0; i < 1024; ++i) { src.get(); } @@ -137,24 +130,28 @@ public class ByteBufferPerfTest { } @Test - public void timeByteBuffer_getByteArray() throws Exception { - ByteBuffer src = ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType); + @Parameters(method = "getData") + public void timeByteBuffer_getByteArray( + MyByteOrder byteOrder, boolean aligned, MyBufferType bufferType) throws Exception { + ByteBuffer src = ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType); byte[] dst = new byte[1024]; BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { for (int i = 0; i < 1024; ++i) { - src.position(mAligned ? 0 : 1); + src.position(aligned ? 0 : 1); src.get(dst); } } } @Test - public void timeByteBuffer_getByte_indexed() throws Exception { - ByteBuffer src = ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType); + @Parameters(method = "getData") + public void timeByteBuffer_getByte_indexed( + MyByteOrder byteOrder, boolean aligned, MyBufferType bufferType) throws Exception { + ByteBuffer src = ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType); BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { - src.position(mAligned ? 0 : 1); + src.position(aligned ? 0 : 1); for (int i = 0; i < 1024; ++i) { src.get(i); } @@ -162,11 +159,13 @@ public class ByteBufferPerfTest { } @Test - public void timeByteBuffer_getChar() throws Exception { - ByteBuffer src = ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType); + @Parameters(method = "getData") + public void timeByteBuffer_getChar( + MyByteOrder byteOrder, boolean aligned, MyBufferType bufferType) throws Exception { + ByteBuffer src = ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType); BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { - src.position(mAligned ? 0 : 1); + src.position(aligned ? 0 : 1); for (int i = 0; i < 1024; ++i) { src.getChar(); } @@ -174,9 +173,11 @@ public class ByteBufferPerfTest { } @Test - public void timeCharBuffer_getCharArray() throws Exception { + @Parameters(method = "getData") + public void timeCharBuffer_getCharArray( + MyByteOrder byteOrder, boolean aligned, MyBufferType bufferType) throws Exception { CharBuffer src = - ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType).asCharBuffer(); + ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType).asCharBuffer(); char[] dst = new char[1024]; BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { @@ -188,11 +189,13 @@ public class ByteBufferPerfTest { } @Test - public void timeByteBuffer_getChar_indexed() throws Exception { - ByteBuffer src = ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType); + @Parameters(method = "getData") + public void timeByteBuffer_getChar_indexed( + MyByteOrder byteOrder, boolean aligned, MyBufferType bufferType) throws Exception { + ByteBuffer src = ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType); BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { - src.position(mAligned ? 0 : 1); + src.position(aligned ? 0 : 1); for (int i = 0; i < 1024; ++i) { src.getChar(i * 2); } @@ -200,11 +203,13 @@ public class ByteBufferPerfTest { } @Test - public void timeByteBuffer_getDouble() throws Exception { - ByteBuffer src = ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType); + @Parameters(method = "getData") + public void timeByteBuffer_getDouble( + MyByteOrder byteOrder, boolean aligned, MyBufferType bufferType) throws Exception { + ByteBuffer src = ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType); BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { - src.position(mAligned ? 0 : 1); + src.position(aligned ? 0 : 1); for (int i = 0; i < 1024; ++i) { src.getDouble(); } @@ -212,9 +217,11 @@ public class ByteBufferPerfTest { } @Test - public void timeDoubleBuffer_getDoubleArray() throws Exception { + @Parameters(method = "getData") + public void timeDoubleBuffer_getDoubleArray( + MyByteOrder byteOrder, boolean aligned, MyBufferType bufferType) throws Exception { DoubleBuffer src = - ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType).asDoubleBuffer(); + ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType).asDoubleBuffer(); double[] dst = new double[1024]; BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { @@ -226,11 +233,13 @@ public class ByteBufferPerfTest { } @Test - public void timeByteBuffer_getFloat() throws Exception { - ByteBuffer src = ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType); + @Parameters(method = "getData") + public void timeByteBuffer_getFloat( + MyByteOrder byteOrder, boolean aligned, MyBufferType bufferType) throws Exception { + ByteBuffer src = ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType); BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { - src.position(mAligned ? 0 : 1); + src.position(aligned ? 0 : 1); for (int i = 0; i < 1024; ++i) { src.getFloat(); } @@ -238,9 +247,11 @@ public class ByteBufferPerfTest { } @Test - public void timeFloatBuffer_getFloatArray() throws Exception { + @Parameters(method = "getData") + public void timeFloatBuffer_getFloatArray( + MyByteOrder byteOrder, boolean aligned, MyBufferType bufferType) throws Exception { FloatBuffer src = - ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType).asFloatBuffer(); + ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType).asFloatBuffer(); float[] dst = new float[1024]; BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { @@ -252,11 +263,13 @@ public class ByteBufferPerfTest { } @Test - public void timeByteBuffer_getInt() throws Exception { - ByteBuffer src = ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType); + @Parameters(method = "getData") + public void timeByteBuffer_getInt( + MyByteOrder byteOrder, boolean aligned, MyBufferType bufferType) throws Exception { + ByteBuffer src = ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType); BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { - src.position(mAligned ? 0 : 1); + src.position(aligned ? 0 : 1); for (int i = 0; i < 1024; ++i) { src.getInt(); } @@ -264,9 +277,10 @@ public class ByteBufferPerfTest { } @Test - public void timeIntBuffer_getIntArray() throws Exception { - IntBuffer src = - ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType).asIntBuffer(); + @Parameters(method = "getData") + public void timeIntBuffer_getIntArray( + MyByteOrder byteOrder, boolean aligned, MyBufferType bufferType) throws Exception { + IntBuffer src = ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType).asIntBuffer(); int[] dst = new int[1024]; BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { @@ -278,11 +292,13 @@ public class ByteBufferPerfTest { } @Test - public void timeByteBuffer_getLong() throws Exception { - ByteBuffer src = ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType); + @Parameters(method = "getData") + public void timeByteBuffer_getLong( + MyByteOrder byteOrder, boolean aligned, MyBufferType bufferType) throws Exception { + ByteBuffer src = ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType); BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { - src.position(mAligned ? 0 : 1); + src.position(aligned ? 0 : 1); for (int i = 0; i < 1024; ++i) { src.getLong(); } @@ -290,9 +306,11 @@ public class ByteBufferPerfTest { } @Test - public void timeLongBuffer_getLongArray() throws Exception { + @Parameters(method = "getData") + public void timeLongBuffer_getLongArray( + MyByteOrder byteOrder, boolean aligned, MyBufferType bufferType) throws Exception { LongBuffer src = - ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType).asLongBuffer(); + ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType).asLongBuffer(); long[] dst = new long[1024]; BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { @@ -304,11 +322,13 @@ public class ByteBufferPerfTest { } @Test - public void timeByteBuffer_getShort() throws Exception { - ByteBuffer src = ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType); + @Parameters(method = "getData") + public void timeByteBuffer_getShort( + MyByteOrder byteOrder, boolean aligned, MyBufferType bufferType) throws Exception { + ByteBuffer src = ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType); BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { - src.position(mAligned ? 0 : 1); + src.position(aligned ? 0 : 1); for (int i = 0; i < 1024; ++i) { src.getShort(); } @@ -316,9 +336,11 @@ public class ByteBufferPerfTest { } @Test - public void timeShortBuffer_getShortArray() throws Exception { + @Parameters(method = "getData") + public void timeShortBuffer_getShortArray( + MyByteOrder byteOrder, boolean aligned, MyBufferType bufferType) throws Exception { ShortBuffer src = - ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType).asShortBuffer(); + ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType).asShortBuffer(); short[] dst = new short[1024]; BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { @@ -334,8 +356,10 @@ public class ByteBufferPerfTest { // @Test - public void timeByteBuffer_putByte() throws Exception { - ByteBuffer src = ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType); + @Parameters(method = "getData") + public void timeByteBuffer_putByte( + MyByteOrder byteOrder, boolean aligned, MyBufferType bufferType) throws Exception { + ByteBuffer src = ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType); BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { src.position(0); @@ -346,24 +370,28 @@ public class ByteBufferPerfTest { } @Test - public void timeByteBuffer_putByteArray() throws Exception { - ByteBuffer dst = ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType); + @Parameters(method = "getData") + public void timeByteBuffer_putByteArray( + MyByteOrder byteOrder, boolean aligned, MyBufferType bufferType) throws Exception { + ByteBuffer dst = ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType); byte[] src = new byte[1024]; BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { for (int i = 0; i < 1024; ++i) { - dst.position(mAligned ? 0 : 1); + dst.position(aligned ? 0 : 1); dst.put(src); } } } @Test - public void timeByteBuffer_putChar() throws Exception { - ByteBuffer src = ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType); + @Parameters(method = "getData") + public void timeByteBuffer_putChar( + MyByteOrder byteOrder, boolean aligned, MyBufferType bufferType) throws Exception { + ByteBuffer src = ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType); BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { - src.position(mAligned ? 0 : 1); + src.position(aligned ? 0 : 1); for (int i = 0; i < 1024; ++i) { src.putChar(' '); } @@ -371,9 +399,11 @@ public class ByteBufferPerfTest { } @Test - public void timeCharBuffer_putCharArray() throws Exception { + @Parameters(method = "getData") + public void timeCharBuffer_putCharArray( + MyByteOrder byteOrder, boolean aligned, MyBufferType bufferType) throws Exception { CharBuffer dst = - ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType).asCharBuffer(); + ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType).asCharBuffer(); char[] src = new char[1024]; BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { @@ -385,11 +415,13 @@ public class ByteBufferPerfTest { } @Test - public void timeByteBuffer_putDouble() throws Exception { - ByteBuffer src = ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType); + @Parameters(method = "getData") + public void timeByteBuffer_putDouble( + MyByteOrder byteOrder, boolean aligned, MyBufferType bufferType) throws Exception { + ByteBuffer src = ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType); BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { - src.position(mAligned ? 0 : 1); + src.position(aligned ? 0 : 1); for (int i = 0; i < 1024; ++i) { src.putDouble(0.0); } @@ -397,9 +429,11 @@ public class ByteBufferPerfTest { } @Test - public void timeDoubleBuffer_putDoubleArray() throws Exception { + @Parameters(method = "getData") + public void timeDoubleBuffer_putDoubleArray( + MyByteOrder byteOrder, boolean aligned, MyBufferType bufferType) throws Exception { DoubleBuffer dst = - ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType).asDoubleBuffer(); + ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType).asDoubleBuffer(); double[] src = new double[1024]; BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { @@ -411,11 +445,13 @@ public class ByteBufferPerfTest { } @Test - public void timeByteBuffer_putFloat() throws Exception { - ByteBuffer src = ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType); + @Parameters(method = "getData") + public void timeByteBuffer_putFloat( + MyByteOrder byteOrder, boolean aligned, MyBufferType bufferType) throws Exception { + ByteBuffer src = ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType); BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { - src.position(mAligned ? 0 : 1); + src.position(aligned ? 0 : 1); for (int i = 0; i < 1024; ++i) { src.putFloat(0.0f); } @@ -423,9 +459,11 @@ public class ByteBufferPerfTest { } @Test - public void timeFloatBuffer_putFloatArray() throws Exception { + @Parameters(method = "getData") + public void timeFloatBuffer_putFloatArray( + MyByteOrder byteOrder, boolean aligned, MyBufferType bufferType) throws Exception { FloatBuffer dst = - ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType).asFloatBuffer(); + ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType).asFloatBuffer(); float[] src = new float[1024]; BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { @@ -437,11 +475,13 @@ public class ByteBufferPerfTest { } @Test - public void timeByteBuffer_putInt() throws Exception { - ByteBuffer src = ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType); + @Parameters(method = "getData") + public void timeByteBuffer_putInt( + MyByteOrder byteOrder, boolean aligned, MyBufferType bufferType) throws Exception { + ByteBuffer src = ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType); BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { - src.position(mAligned ? 0 : 1); + src.position(aligned ? 0 : 1); for (int i = 0; i < 1024; ++i) { src.putInt(0); } @@ -449,9 +489,10 @@ public class ByteBufferPerfTest { } @Test - public void timeIntBuffer_putIntArray() throws Exception { - IntBuffer dst = - ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType).asIntBuffer(); + @Parameters(method = "getData") + public void timeIntBuffer_putIntArray( + MyByteOrder byteOrder, boolean aligned, MyBufferType bufferType) throws Exception { + IntBuffer dst = ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType).asIntBuffer(); int[] src = new int[1024]; BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { @@ -463,11 +504,13 @@ public class ByteBufferPerfTest { } @Test - public void timeByteBuffer_putLong() throws Exception { - ByteBuffer src = ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType); + @Parameters(method = "getData") + public void timeByteBuffer_putLong( + MyByteOrder byteOrder, boolean aligned, MyBufferType bufferType) throws Exception { + ByteBuffer src = ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType); BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { - src.position(mAligned ? 0 : 1); + src.position(aligned ? 0 : 1); for (int i = 0; i < 1024; ++i) { src.putLong(0L); } @@ -475,9 +518,11 @@ public class ByteBufferPerfTest { } @Test - public void timeLongBuffer_putLongArray() throws Exception { + @Parameters(method = "getData") + public void timeLongBuffer_putLongArray( + MyByteOrder byteOrder, boolean aligned, MyBufferType bufferType) throws Exception { LongBuffer dst = - ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType).asLongBuffer(); + ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType).asLongBuffer(); long[] src = new long[1024]; BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { @@ -489,11 +534,13 @@ public class ByteBufferPerfTest { } @Test - public void timeByteBuffer_putShort() throws Exception { - ByteBuffer src = ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType); + @Parameters(method = "getData") + public void timeByteBuffer_putShort( + MyByteOrder byteOrder, boolean aligned, MyBufferType bufferType) throws Exception { + ByteBuffer src = ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType); BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { - src.position(mAligned ? 0 : 1); + src.position(aligned ? 0 : 1); for (int i = 0; i < 1024; ++i) { src.putShort((short) 0); } @@ -501,9 +548,11 @@ public class ByteBufferPerfTest { } @Test - public void timeShortBuffer_putShortArray() throws Exception { + @Parameters(method = "getData") + public void timeShortBuffer_putShortArray( + MyByteOrder byteOrder, boolean aligned, MyBufferType bufferType) throws Exception { ShortBuffer dst = - ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType).asShortBuffer(); + ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType).asShortBuffer(); short[] src = new short[1024]; BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { @@ -515,6 +564,7 @@ public class ByteBufferPerfTest { } @Test + @Parameters(method = "getData") public void time_new_byteArray() throws Exception { BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { @@ -523,6 +573,7 @@ public class ByteBufferPerfTest { } @Test + @Parameters(method = "getData") public void time_ByteBuffer_allocate() throws Exception { BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { 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 81f9e59f2423..5dd9d6e2bc2c 100644 --- a/apct-tests/perftests/core/src/android/libcore/regression/ByteBufferScalarVersusVectorPerfTest.java +++ b/apct-tests/perftests/core/src/android/libcore/regression/ByteBufferScalarVersusVectorPerfTest.java @@ -20,23 +20,23 @@ import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; import android.test.suitebuilder.annotation.LargeTest; +import junitparams.JUnitParamsRunner; +import junitparams.Parameters; + import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; import java.nio.ByteBuffer; import java.util.Arrays; import java.util.Collection; -@RunWith(Parameterized.class) +@RunWith(JUnitParamsRunner.class) @LargeTest public class ByteBufferScalarVersusVectorPerfTest { @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter(); - @Parameters(name = "mByteOrder={0}, mAligned={1}, mBufferType={2}") - public static Collection<Object[]> data() { + public static Collection<Object[]> getData() { return Arrays.asList( new Object[][] { { @@ -102,19 +102,15 @@ public class ByteBufferScalarVersusVectorPerfTest { }); } - @Parameterized.Parameter(0) - public ByteBufferPerfTest.MyByteOrder mByteOrder; - - @Parameterized.Parameter(1) - public boolean mAligned; - - @Parameterized.Parameter(2) - public ByteBufferPerfTest.MyBufferType mBufferType; - @Test - public void timeManualByteBufferCopy() throws Exception { - ByteBuffer src = ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType); - ByteBuffer dst = ByteBufferPerfTest.newBuffer(mByteOrder, mAligned, mBufferType); + @Parameters(method = "getData") + public void timeManualByteBufferCopy( + ByteBufferPerfTest.MyByteOrder byteOrder, + boolean aligned, + ByteBufferPerfTest.MyBufferType bufferType) + throws Exception { + ByteBuffer src = ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType); + ByteBuffer dst = ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType); BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { src.position(0); @@ -126,23 +122,25 @@ public class ByteBufferScalarVersusVectorPerfTest { } @Test - public void timeByteBufferBulkGet() throws Exception { - ByteBuffer src = ByteBuffer.allocate(mAligned ? 8192 : 8192 + 1); + @Parameters({"true", "false"}) + public void timeByteBufferBulkGet(boolean aligned) throws Exception { + ByteBuffer src = ByteBuffer.allocate(aligned ? 8192 : 8192 + 1); byte[] dst = new byte[8192]; BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { - src.position(mAligned ? 0 : 1); + src.position(aligned ? 0 : 1); src.get(dst, 0, dst.length); } } @Test - public void timeDirectByteBufferBulkGet() throws Exception { - ByteBuffer src = ByteBuffer.allocateDirect(mAligned ? 8192 : 8192 + 1); + @Parameters({"true", "false"}) + public void timeDirectByteBufferBulkGet(boolean aligned) throws Exception { + ByteBuffer src = ByteBuffer.allocateDirect(aligned ? 8192 : 8192 + 1); byte[] dst = new byte[8192]; BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { - src.position(mAligned ? 0 : 1); + 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 28ec6ded3c86..0a598998bced 100644 --- a/apct-tests/perftests/core/src/android/libcore/regression/CharacterPerfTest.java +++ b/apct-tests/perftests/core/src/android/libcore/regression/CharacterPerfTest.java @@ -20,12 +20,12 @@ import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; import android.test.suitebuilder.annotation.LargeTest; -import org.junit.Before; +import junitparams.JUnitParamsRunner; +import junitparams.Parameters; + import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; import java.util.Arrays; import java.util.Collection; @@ -34,13 +34,12 @@ import java.util.Collection; * Tests various Character methods, intended for testing multiple implementations against each * other. */ -@RunWith(Parameterized.class) +@RunWith(JUnitParamsRunner.class) @LargeTest public class CharacterPerfTest { @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter(); - @Parameters(name = "mCharacterSet({0}), mOverload({1})") - public static Collection<Object[]> data() { + public static Collection<Object[]> getData() { return Arrays.asList( new Object[][] { {CharacterSet.ASCII, Overload.CHAR}, @@ -50,17 +49,10 @@ public class CharacterPerfTest { }); } - @Parameterized.Parameter(0) - public CharacterSet mCharacterSet; - - @Parameterized.Parameter(1) - public Overload mOverload; - private char[] mChars; - @Before - public void setUp() throws Exception { - this.mChars = mCharacterSet.mChars; + public void setUp(CharacterSet characterSet) { + this.mChars = characterSet.mChars; } public enum Overload { @@ -87,10 +79,12 @@ public class CharacterPerfTest { // A fake benchmark to give us a baseline. @Test - public void timeIsSpace() { + @Parameters(method = "getData") + public void timeIsSpace(CharacterSet characterSet, Overload overload) { + setUp(characterSet); boolean fake = false; BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); - if (mOverload == Overload.CHAR) { + if (overload == Overload.CHAR) { while (state.keepRunning()) { for (int ch = 0; ch < 65536; ++ch) { fake ^= ((char) ch == ' '); @@ -106,9 +100,11 @@ public class CharacterPerfTest { } @Test - public void timeDigit() { + @Parameters(method = "getData") + public void timeDigit(CharacterSet characterSet, Overload overload) { + setUp(characterSet); BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); - if (mOverload == Overload.CHAR) { + if (overload == Overload.CHAR) { while (state.keepRunning()) { for (int ch = 0; ch < 65536; ++ch) { Character.digit(mChars[ch], 10); @@ -124,9 +120,11 @@ public class CharacterPerfTest { } @Test - public void timeGetNumericValue() { + @Parameters(method = "getData") + public void timeGetNumericValue(CharacterSet characterSet, Overload overload) { + setUp(characterSet); BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); - if (mOverload == Overload.CHAR) { + if (overload == Overload.CHAR) { while (state.keepRunning()) { for (int ch = 0; ch < 65536; ++ch) { Character.getNumericValue(mChars[ch]); @@ -142,9 +140,11 @@ public class CharacterPerfTest { } @Test - public void timeIsDigit() { + @Parameters(method = "getData") + public void timeIsDigit(CharacterSet characterSet, Overload overload) { + setUp(characterSet); BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); - if (mOverload == Overload.CHAR) { + if (overload == Overload.CHAR) { while (state.keepRunning()) { for (int ch = 0; ch < 65536; ++ch) { Character.isDigit(mChars[ch]); @@ -160,9 +160,11 @@ public class CharacterPerfTest { } @Test - public void timeIsIdentifierIgnorable() { + @Parameters(method = "getData") + public void timeIsIdentifierIgnorable(CharacterSet characterSet, Overload overload) { + setUp(characterSet); BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); - if (mOverload == Overload.CHAR) { + if (overload == Overload.CHAR) { while (state.keepRunning()) { for (int ch = 0; ch < 65536; ++ch) { Character.isIdentifierIgnorable(mChars[ch]); @@ -178,9 +180,11 @@ public class CharacterPerfTest { } @Test - public void timeIsJavaIdentifierPart() { + @Parameters(method = "getData") + public void timeIsJavaIdentifierPart(CharacterSet characterSet, Overload overload) { + setUp(characterSet); BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); - if (mOverload == Overload.CHAR) { + if (overload == Overload.CHAR) { while (state.keepRunning()) { for (int ch = 0; ch < 65536; ++ch) { Character.isJavaIdentifierPart(mChars[ch]); @@ -196,9 +200,11 @@ public class CharacterPerfTest { } @Test - public void timeIsJavaIdentifierStart() { + @Parameters(method = "getData") + public void timeIsJavaIdentifierStart(CharacterSet characterSet, Overload overload) { + setUp(characterSet); BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); - if (mOverload == Overload.CHAR) { + if (overload == Overload.CHAR) { while (state.keepRunning()) { for (int ch = 0; ch < 65536; ++ch) { Character.isJavaIdentifierStart(mChars[ch]); @@ -214,9 +220,11 @@ public class CharacterPerfTest { } @Test - public void timeIsLetter() { + @Parameters(method = "getData") + public void timeIsLetter(CharacterSet characterSet, Overload overload) { + setUp(characterSet); BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); - if (mOverload == Overload.CHAR) { + if (overload == Overload.CHAR) { while (state.keepRunning()) { for (int ch = 0; ch < 65536; ++ch) { Character.isLetter(mChars[ch]); @@ -232,9 +240,11 @@ public class CharacterPerfTest { } @Test - public void timeIsLetterOrDigit() { + @Parameters(method = "getData") + public void timeIsLetterOrDigit(CharacterSet characterSet, Overload overload) { + setUp(characterSet); BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); - if (mOverload == Overload.CHAR) { + if (overload == Overload.CHAR) { while (state.keepRunning()) { for (int ch = 0; ch < 65536; ++ch) { Character.isLetterOrDigit(mChars[ch]); @@ -250,9 +260,11 @@ public class CharacterPerfTest { } @Test - public void timeIsLowerCase() { + @Parameters(method = "getData") + public void timeIsLowerCase(CharacterSet characterSet, Overload overload) { + setUp(characterSet); BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); - if (mOverload == Overload.CHAR) { + if (overload == Overload.CHAR) { while (state.keepRunning()) { for (int ch = 0; ch < 65536; ++ch) { Character.isLowerCase(mChars[ch]); @@ -268,9 +280,11 @@ public class CharacterPerfTest { } @Test - public void timeIsSpaceChar() { + @Parameters(method = "getData") + public void timeIsSpaceChar(CharacterSet characterSet, Overload overload) { + setUp(characterSet); BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); - if (mOverload == Overload.CHAR) { + if (overload == Overload.CHAR) { while (state.keepRunning()) { for (int ch = 0; ch < 65536; ++ch) { Character.isSpaceChar(mChars[ch]); @@ -286,9 +300,11 @@ public class CharacterPerfTest { } @Test - public void timeIsUpperCase() { + @Parameters(method = "getData") + public void timeIsUpperCase(CharacterSet characterSet, Overload overload) { + setUp(characterSet); BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); - if (mOverload == Overload.CHAR) { + if (overload == Overload.CHAR) { while (state.keepRunning()) { for (int ch = 0; ch < 65536; ++ch) { Character.isUpperCase(mChars[ch]); @@ -304,9 +320,11 @@ public class CharacterPerfTest { } @Test - public void timeIsWhitespace() { + @Parameters(method = "getData") + public void timeIsWhitespace(CharacterSet characterSet, Overload overload) { + setUp(characterSet); BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); - if (mOverload == Overload.CHAR) { + if (overload == Overload.CHAR) { while (state.keepRunning()) { for (int ch = 0; ch < 65536; ++ch) { Character.isWhitespace(mChars[ch]); @@ -322,9 +340,11 @@ public class CharacterPerfTest { } @Test - public void timeToLowerCase() { + @Parameters(method = "getData") + public void timeToLowerCase(CharacterSet characterSet, Overload overload) { + setUp(characterSet); BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); - if (mOverload == Overload.CHAR) { + if (overload == Overload.CHAR) { while (state.keepRunning()) { for (int ch = 0; ch < 65536; ++ch) { Character.toLowerCase(mChars[ch]); @@ -340,9 +360,11 @@ public class CharacterPerfTest { } @Test - public void timeToUpperCase() { + @Parameters(method = "getData") + public void timeToUpperCase(CharacterSet characterSet, Overload overload) { + setUp(characterSet); BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); - if (mOverload == Overload.CHAR) { + if (overload == Overload.CHAR) { while (state.keepRunning()) { for (int ch = 0; ch < 65536; ++ch) { Character.toUpperCase(mChars[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 603b182e7c36..8da13a9b7f91 100644 --- a/apct-tests/perftests/core/src/android/libcore/regression/CharsetForNamePerfTest.java +++ b/apct-tests/perftests/core/src/android/libcore/regression/CharsetForNamePerfTest.java @@ -20,44 +20,40 @@ import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; import android.test.suitebuilder.annotation.LargeTest; +import junitparams.JUnitParamsRunner; +import junitparams.Parameters; + import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; import java.nio.charset.Charset; -import java.util.Arrays; -import java.util.Collection; -@RunWith(Parameterized.class) +@RunWith(JUnitParamsRunner.class) @LargeTest public class CharsetForNamePerfTest { @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter(); - @Parameterized.Parameters(name = "mCharsetName({0})") - public static Collection<Object[]> data() { - return Arrays.asList( - new Object[][] { - {"UTF-16"}, - {"UTF-8"}, - {"UTF8"}, - {"ISO-8859-1"}, - {"8859_1"}, - {"ISO-8859-2"}, - {"8859_2"}, - {"US-ASCII"}, - {"ASCII"}, - }); + public static String[] charsetNames() { + return new String[] { + "UTF-16", + "UTF-8", + "UTF8", + "ISO-8859-1", + "8859_1", + "ISO-8859-2", + "8859_2", + "US-ASCII", + "ASCII", + }; } - @Parameterized.Parameter(0) - public String mCharsetName; - @Test - public void timeCharsetForName() throws Exception { + @Parameters(method = "charsetNames") + public void timeCharsetForName(String charsetName) throws Exception { BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { - Charset.forName(mCharsetName); + 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 437d186834e0..048c50f044c8 100644 --- a/apct-tests/perftests/core/src/android/libcore/regression/CharsetPerfTest.java +++ b/apct-tests/perftests/core/src/android/libcore/regression/CharsetPerfTest.java @@ -20,22 +20,22 @@ import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; import android.test.suitebuilder.annotation.LargeTest; +import junitparams.JUnitParamsRunner; +import junitparams.Parameters; + import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; import java.util.Arrays; import java.util.Collection; -@RunWith(Parameterized.class) +@RunWith(JUnitParamsRunner.class) @LargeTest public class CharsetPerfTest { @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter(); - @Parameters(name = "mLength({0}), mName({1})") - public static Collection<Object[]> data() { + public static Collection<Object[]> getData() { return Arrays.asList( new Object[][] { {1, "UTF-16"}, @@ -86,24 +86,20 @@ public class CharsetPerfTest { }); } - @Parameterized.Parameter(0) - public int mLength; - - @Parameterized.Parameter(1) - public String mName; - @Test - public void time_new_String_BString() throws Exception { - byte[] bytes = makeBytes(makeString(mLength)); + @Parameters(method = "getData") + public void time_new_String_BString(int length, String name) throws Exception { + byte[] bytes = makeBytes(makeString(length)); BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { - new String(bytes, mName); + new String(bytes, name); } } @Test - public void time_new_String_BII() throws Exception { - byte[] bytes = makeBytes(makeString(mLength)); + @Parameters(method = "getData") + public void time_new_String_BII(int length, String name) throws Exception { + byte[] bytes = makeBytes(makeString(length)); BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { new String(bytes, 0, bytes.length); @@ -111,20 +107,22 @@ public class CharsetPerfTest { } @Test - public void time_new_String_BIIString() throws Exception { - byte[] bytes = makeBytes(makeString(mLength)); + @Parameters(method = "getData") + public void time_new_String_BIIString(int length, String name) throws Exception { + byte[] bytes = makeBytes(makeString(length)); BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { - new String(bytes, 0, bytes.length, mName); + new String(bytes, 0, bytes.length, name); } } @Test - public void time_String_getBytes() throws Exception { - String string = makeString(mLength); + @Parameters(method = "getData") + public void time_String_getBytes(int length, String name) throws Exception { + String string = makeString(length); BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { - string.getBytes(mName); + string.getBytes(name); } } 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 15c27f2366e1..42b058815bfe 100644 --- a/apct-tests/perftests/core/src/android/libcore/regression/CipherPerfTest.java +++ b/apct-tests/perftests/core/src/android/libcore/regression/CipherPerfTest.java @@ -20,11 +20,12 @@ import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; import android.test.suitebuilder.annotation.LargeTest; -import org.junit.Before; +import junitparams.JUnitParamsRunner; +import junitparams.Parameters; + import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; import java.security.spec.AlgorithmParameterSpec; import java.util.ArrayList; @@ -42,17 +43,13 @@ import javax.crypto.spec.IvParameterSpec; * Cipher benchmarks. Only runs on AES currently because of the combinatorial explosion of the test * as it stands. */ -@RunWith(Parameterized.class) +@RunWith(JUnitParamsRunner.class) @LargeTest public class CipherPerfTest { @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter(); - @Parameterized.Parameters( - name = - "mMode({0}), mPadding({1}), mKeySize({2}), mInputSize({3})," - + " mImplementation({4})") - public static Collection cases() { - int[] mKeySizes = new int[] {128, 192, 256}; + public static Collection getCases() { + int[] keySizes = new int[] {128, 192, 256}; int[] inputSizes = new int[] {16, 32, 64, 128, 1024, 8192}; final List<Object[]> params = new ArrayList<>(); for (Mode mode : Mode.values()) { @@ -71,11 +68,11 @@ public class CipherPerfTest { && implementation == Implementation.OpenSSL) { continue; } - for (int mKeySize : mKeySizes) { + for (int keySize : keySizes) { for (int inputSize : inputSizes) { params.add( new Object[] { - mode, padding, mKeySize, inputSize, implementation + mode, padding, keySize, inputSize, implementation }); } } @@ -107,9 +104,6 @@ public class CipherPerfTest { AES, }; - @Parameterized.Parameter(0) - public Mode mMode; - public enum Mode { CBC, CFB, @@ -118,23 +112,11 @@ public class CipherPerfTest { OFB, }; - @Parameterized.Parameter(1) - public Padding mPadding; - public enum Padding { NOPADDING, PKCS1PADDING, }; - @Parameterized.Parameter(2) - public int mKeySize; - - @Parameterized.Parameter(3) - public int mInputSize; - - @Parameterized.Parameter(4) - public Implementation mImplementation; - public enum Implementation { OpenSSL, BouncyCastle @@ -156,21 +138,20 @@ public class CipherPerfTest { private AlgorithmParameterSpec mSpec; - @Before - public void setUp() throws Exception { - mCipherAlgorithm = - mAlgorithm.toString() + "/" + mMode.toString() + "/" + mPadding.toString(); + public void setUp(Mode mode, Padding padding, int keySize, Implementation implementation) + throws Exception { + mCipherAlgorithm = mAlgorithm.toString() + "/" + mode.toString() + "/" + padding.toString(); String mKeyAlgorithm = mAlgorithm.toString(); - mKey = sKeySizes.get(mKeySize); + mKey = sKeySizes.get(keySize); if (mKey == null) { KeyGenerator generator = KeyGenerator.getInstance(mKeyAlgorithm); - generator.init(mKeySize); + generator.init(keySize); mKey = generator.generateKey(); - sKeySizes.put(mKeySize, mKey); + sKeySizes.put(keySize, mKey); } - switch (mImplementation) { + switch (implementation) { case OpenSSL: mProviderName = "AndroidOpenSSL"; break; @@ -178,10 +159,10 @@ public class CipherPerfTest { mProviderName = "BC"; break; default: - throw new RuntimeException(mImplementation.toString()); + throw new RuntimeException(implementation.toString()); } - if (mMode != Mode.ECB) { + if (mode != Mode.ECB) { mSpec = new IvParameterSpec(IV); } @@ -193,18 +174,26 @@ public class CipherPerfTest { } @Test - public void timeEncrypt() throws Exception { + @Parameters(method = "getCases") + public void timeEncrypt( + Mode mode, Padding padding, int keySize, int inputSize, Implementation implementation) + throws Exception { + setUp(mode, padding, keySize, implementation); BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { - mCipherEncrypt.doFinal(DATA, 0, mInputSize, mOutput); + mCipherEncrypt.doFinal(DATA, 0, inputSize, mOutput); } } @Test - public void timeDecrypt() throws Exception { + @Parameters(method = "getCases") + public void timeDecrypt( + Mode mode, Padding padding, int keySize, int inputSize, Implementation implementation) + throws Exception { + setUp(mode, padding, keySize, implementation); BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { - mCipherDecrypt.doFinal(DATA, 0, mInputSize, mOutput); + mCipherDecrypt.doFinal(DATA, 0, inputSize, mOutput); } } } 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 a89efffcdd1f..69197c3325f4 100644 --- a/apct-tests/perftests/core/src/android/libcore/regression/CollectionsPerfTest.java +++ b/apct-tests/perftests/core/src/android/libcore/regression/CollectionsPerfTest.java @@ -20,11 +20,12 @@ import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; import android.test.suitebuilder.annotation.LargeTest; +import junitparams.JUnitParamsRunner; +import junitparams.Parameters; + import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; import java.util.ArrayList; import java.util.Arrays; @@ -35,19 +36,15 @@ import java.util.List; import java.util.Random; import java.util.Vector; -@RunWith(Parameterized.class) +@RunWith(JUnitParamsRunner.class) @LargeTest public class CollectionsPerfTest { @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter(); - @Parameters(name = "mArrayListLength({0})") - public static Collection<Object[]> data() { + public static Collection<Object[]> getData() { return Arrays.asList(new Object[][] {{4}, {16}, {64}, {256}, {1024}}); } - @Parameterized.Parameter(0) - public int arrayListLength; - public static Comparator<Integer> REVERSE = new Comparator<Integer>() { @Override @@ -59,7 +56,8 @@ public class CollectionsPerfTest { }; @Test - public void timeSort_arrayList() throws Exception { + @Parameters(method = "getData") + public void timeSort_arrayList(int arrayListLength) throws Exception { List<Integer> input = buildList(arrayListLength, ArrayList.class); BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { @@ -68,7 +66,8 @@ public class CollectionsPerfTest { } @Test - public void timeSortWithComparator_arrayList() throws Exception { + @Parameters(method = "getData") + public void timeSortWithComparator_arrayList(int arrayListLength) throws Exception { List<Integer> input = buildList(arrayListLength, ArrayList.class); BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { @@ -77,7 +76,8 @@ public class CollectionsPerfTest { } @Test - public void timeSort_vector() throws Exception { + @Parameters(method = "getData") + public void timeSort_vector(int arrayListLength) throws Exception { List<Integer> input = buildList(arrayListLength, Vector.class); BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { @@ -86,7 +86,8 @@ public class CollectionsPerfTest { } @Test - public void timeSortWithComparator_vector() throws Exception { + @Parameters(method = "getData") + public void timeSortWithComparator_vector(int arrayListLength) throws Exception { List<Integer> input = buildList(arrayListLength, Vector.class); BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { 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 4ff3ba5b0aaa..839120336697 100644 --- a/apct-tests/perftests/core/src/android/libcore/regression/EqualsHashCodePerfTest.java +++ b/apct-tests/perftests/core/src/android/libcore/regression/EqualsHashCodePerfTest.java @@ -20,11 +20,12 @@ import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; import android.test.suitebuilder.annotation.LargeTest; -import org.junit.Before; +import junitparams.JUnitParamsRunner; +import junitparams.Parameters; + import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; import java.net.URI; import java.net.URL; @@ -32,39 +33,39 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; -@RunWith(Parameterized.class) +@RunWith(JUnitParamsRunner.class) @LargeTest public final class EqualsHashCodePerfTest { @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter(); private enum Type { URI() { - @Override Object newInstance(String text) throws Exception { + @Override + Object newInstance(String text) throws Exception { return new URI(text); } }, URL() { - @Override Object newInstance(String text) throws Exception { + @Override + Object newInstance(String text) throws Exception { return new URL(text); } }; + abstract Object newInstance(String text) throws Exception; } - private static final String QUERY = "%E0%AE%A8%E0%AE%BE%E0%AE%AE%E0%AF%8D+%E0%AE%AE%E0%AF%81%E0%AE%95%E0%AF%8D%E0%AE%95%E0%AE%BF%E0%AE%AF%E0%AE%AE%E0%AE%BE%E0%AE%A9%2C+%E0%AE%9A%E0%AF%81%E0%AE%B5%E0%AE%BE%E0%AE%B0%E0%AE%B8%E0%AF%8D%E0%AE%AF%E0%AE%AE%E0%AE%BE%E0%AE%A9+%E0%AE%87%E0%AE%B0%E0%AF%81%E0%AE%AA%E0%AF%8D%E0%AE%AA%E0%AF%87%E0%AE%BE%E0%AE%AE%E0%AF%8D%2C+%E0%AE%86%E0%AE%A9%E0%AE%BE%E0%AE%B2%E0%AF%8D+%E0%AE%9A%E0%AE%BF%E0%AE%B2+%E0%AE%A8%E0%AF%87%E0%AE%B0%E0%AE%99%E0%AF%8D%E0%AE%95%E0%AE%B3%E0%AE%BF%E0%AE%B2%E0%AF%8D+%E0%AE%9A%E0%AF%82%E0%AE%B4%E0%AF%8D%E0%AE%A8%E0%AE%BF%E0%AE%B2%E0%AF%88+%E0%AE%8F%E0%AE%B1%E0%AF%8D%E0%AE%AA%E0%AE%9F%E0%AF%81%E0%AE%AE%E0%AF%8D+%E0%AE%8E%E0%AE%A9%E0%AF%8D%E0%AE%AA%E0%AE%A4%E0%AE%BE%E0%AE%B2%E0%AF%8D+%E0%AE%AA%E0%AE%A3%E0%AE%BF%E0%AE%AF%E0%AF%88%E0%AE%AF%E0%AF%81%E0%AE%AE%E0%AF%8D+%E0%AE%B5%E0%AE%B2%E0%AE%BF+%E0%AE%85%E0%AE%B5%E0%AE%B0%E0%AF%88+%E0%AE%9A%E0%AE%BF%E0%AE%B2+%E0%AE%AA%E0%AF%86%E0%AE%B0%E0%AE%BF%E0%AE%AF+%E0%AE%95%E0%AF%86%E0%AE%BE%E0%AE%B3%E0%AF%8D%E0%AE%AE%E0%AF%81%E0%AE%A4%E0%AE%B2%E0%AF%8D+%E0%AE%AE%E0%AF%81%E0%AE%9F%E0%AE%BF%E0%AE%AF%E0%AF%81%E0%AE%AE%E0%AF%8D.+%E0%AE%85%E0%AE%A4%E0%AF%81+%E0%AE%9A%E0%AE%BF%E0%AE%B2+%E0%AE%A8%E0%AE%A9%E0%AF%8D%E0%AE%AE%E0%AF%88%E0%AE%95%E0%AE%B3%E0%AF%88+%E0%AE%AA%E0%AF%86%E0%AE%B1+%E0%AE%A4%E0%AE%B5%E0%AE%BF%E0%AE%B0%2C+%E0%AE%8E%E0%AE%AA%E0%AF%8D%E0%AE%AA%E0%AF%87%E0%AE%BE%E0%AE%A4%E0%AF%81%E0%AE%AE%E0%AF%8D+%E0%AE%89%E0%AE%B4%E0%AF%88%E0%AE%95%E0%AF%8D%E0%AE%95+%E0%AE%89%E0%AE%9F%E0%AE%B1%E0%AF%8D%E0%AE%AA%E0%AE%AF%E0%AE%BF%E0%AE%B1%E0%AF%8D%E0%AE%9A%E0%AE%BF+%E0%AE%AE%E0%AF%87%E0%AE%B1%E0%AF%8D%E0%AE%95%E0%AF%86%E0%AE%BE%E0%AE%B3%E0%AF%8D%E0%AE%95%E0%AE%BF%E0%AE%B1%E0%AE%A4%E0%AF%81+%E0%AE%8E%E0%AE%99%E0%AF%8D%E0%AE%95%E0%AE%B3%E0%AF%81%E0%AE%95%E0%AF%8D%E0%AE%95%E0%AF%81+%E0%AE%87%E0%AE%A4%E0%AF%81+%E0%AE%92%E0%AE%B0%E0%AF%81+%E0%AE%9A%E0%AE%BF%E0%AE%B1%E0%AE%BF%E0%AE%AF+%E0%AE%89%E0%AE%A4%E0%AE%BE%E0%AE%B0%E0%AE%A3%E0%AE%AE%E0%AF%8D%2C+%E0%AE%8E%E0%AE%9F%E0%AF%81%E0%AE%95%E0%AF%8D%E0%AE%95.+%E0%AE%B0%E0%AE%AF%E0%AE%BF%E0%AE%B2%E0%AF%8D+%E0%AE%8E%E0%AE%A8%E0%AF%8D%E0%AE%A4+%E0%AE%B5%E0%AE%BF%E0%AE%B3%E0%AF%88%E0%AE%B5%E0%AE%BE%E0%AE%95+%E0%AE%87%E0%AE%A9%E0%AF%8D%E0%AE%AA%E0%AE%AE%E0%AF%8D+%E0%AE%86%E0%AE%A9%E0%AF%8D%E0%AE%B2%E0%AF%88%E0%AE%A9%E0%AF%8D+%E0%AE%AA%E0%AE%AF%E0%AE%A9%E0%AF%8D%E0%AE%AA%E0%AE%BE%E0%AE%9F%E0%AF%81%E0%AE%95%E0%AE%B3%E0%AF%8D+%E0%AE%87%E0%AE%B0%E0%AF%81%E0%AE%95%E0%AF%8D%E0%AE%95+%E0%AE%B5%E0%AF%87%E0%AE%A3%E0%AF%8D%E0%AE%9F%E0%AF%81%E0%AE%AE%E0%AF%8D+%E0%AE%A4%E0%AE%AF%E0%AE%BE%E0%AE%B0%E0%AE%BF%E0%AE%95%E0%AF%8D%E0%AE%95%E0%AF%81%E0%AE%AE%E0%AF%8D+%E0%AE%A4%E0%AE%B5%E0%AE%B1%E0%AF%81+%E0%AE%95%E0%AE%A3%E0%AF%8D%E0%AE%9F%E0%AF%81%E0%AE%AA%E0%AE%BF%E0%AE%9F%E0%AE%BF%E0%AE%95%E0%AF%8D%E0%AE%95+%E0%AE%B5%E0%AE%B0%E0%AF%81%E0%AE%AE%E0%AF%8D+%E0%AE%A8%E0%AE%BE%E0%AE%AE%E0%AF%8D+%E0%AE%A4%E0%AE%B1%E0%AF%8D%E0%AE%AA%E0%AF%87%E0%AE%BE%E0%AE%A4%E0%AF%81+%E0%AE%87%E0%AE%B0%E0%AF%81%E0%AE%95%E0%AF%8D%E0%AE%95%E0%AE%BF%E0%AE%B1%E0%AF%87%E0%AE%BE%E0%AE%AE%E0%AF%8D.+%E0%AE%87%E0%AE%A8%E0%AF%8D%E0%AE%A4+%E0%AE%A8%E0%AE%BF%E0%AE%95%E0%AE%B4%E0%AF%8D%E0%AE%B5%E0%AF%81%E0%AE%95%E0%AE%B3%E0%AE%BF%E0%AE%B2%E0%AF%8D+%E0%AE%9A%E0%AF%86%E0%AE%AF%E0%AF%8D%E0%AE%A4%E0%AE%AA%E0%AE%BF%E0%AE%A9%E0%AF%8D+%E0%AE%85%E0%AE%AE%E0%AF%88%E0%AE%AA%E0%AF%8D%E0%AE%AA%E0%AE%BF%E0%AE%A9%E0%AF%8D+%E0%AE%95%E0%AE%A3%E0%AE%95%E0%AF%8D%E0%AE%95%E0%AF%81%2C+%E0%AE%85%E0%AE%B5%E0%AE%B0%E0%AF%8D%E0%AE%95%E0%AE%B3%E0%AF%8D+%E0%AE%A4%E0%AE%B5%E0%AE%B1%E0%AF%81+%E0%AE%B5%E0%AE%BF%E0%AE%9F%E0%AF%8D%E0%AE%9F%E0%AF%81+quae+%E0%AE%AA%E0%AE%9F%E0%AF%8D%E0%AE%9F%E0%AE%B1%E0%AF%88+%E0%AE%A8%E0%AF%80%E0%AE%99%E0%AF%8D%E0%AE%95%E0%AE%B3%E0%AF%8D+%E0%AE%AA%E0%AE%B0%E0%AE%BF%E0%AE%A8%E0%AF%8D%E0%AE%A4%E0%AF%81%E0%AE%B0%E0%AF%88%E0%AE%95%E0%AF%8D%E0%AE%95%E0%AE%BF%E0%AE%B1%E0%AF%87%E0%AE%BE%E0%AE%AE%E0%AF%8D+%E0%AE%AE%E0%AF%86%E0%AE%A9%E0%AF%8D%E0%AE%AE%E0%AF%88%E0%AE%AF%E0%AE%BE%E0%AE%95+%E0%AE%AE%E0%AE%BE%E0%AE%B1%E0%AF%81%E0%AE%AE%E0%AF%8D"; + private static final String QUERY = + "%E0%AE%A8%E0%AE%BE%E0%AE%AE%E0%AF%8D+%E0%AE%AE%E0%AF%81%E0%AE%95%E0%AF%8D%E0%AE%95%E0%AE%BF%E0%AE%AF%E0%AE%AE%E0%AE%BE%E0%AE%A9%2C+%E0%AE%9A%E0%AF%81%E0%AE%B5%E0%AE%BE%E0%AE%B0%E0%AE%B8%E0%AF%8D%E0%AE%AF%E0%AE%AE%E0%AE%BE%E0%AE%A9+%E0%AE%87%E0%AE%B0%E0%AF%81%E0%AE%AA%E0%AF%8D%E0%AE%AA%E0%AF%87%E0%AE%BE%E0%AE%AE%E0%AF%8D%2C+%E0%AE%86%E0%AE%A9%E0%AE%BE%E0%AE%B2%E0%AF%8D+%E0%AE%9A%E0%AE%BF%E0%AE%B2+%E0%AE%A8%E0%AF%87%E0%AE%B0%E0%AE%99%E0%AF%8D%E0%AE%95%E0%AE%B3%E0%AE%BF%E0%AE%B2%E0%AF%8D+%E0%AE%9A%E0%AF%82%E0%AE%B4%E0%AF%8D%E0%AE%A8%E0%AE%BF%E0%AE%B2%E0%AF%88+%E0%AE%8F%E0%AE%B1%E0%AF%8D%E0%AE%AA%E0%AE%9F%E0%AF%81%E0%AE%AE%E0%AF%8D+%E0%AE%8E%E0%AE%A9%E0%AF%8D%E0%AE%AA%E0%AE%A4%E0%AE%BE%E0%AE%B2%E0%AF%8D+%E0%AE%AA%E0%AE%A3%E0%AE%BF%E0%AE%AF%E0%AF%88%E0%AE%AF%E0%AF%81%E0%AE%AE%E0%AF%8D+%E0%AE%B5%E0%AE%B2%E0%AE%BF+%E0%AE%85%E0%AE%B5%E0%AE%B0%E0%AF%88+%E0%AE%9A%E0%AE%BF%E0%AE%B2+%E0%AE%AA%E0%AF%86%E0%AE%B0%E0%AE%BF%E0%AE%AF+%E0%AE%95%E0%AF%86%E0%AE%BE%E0%AE%B3%E0%AF%8D%E0%AE%AE%E0%AF%81%E0%AE%A4%E0%AE%B2%E0%AF%8D+%E0%AE%AE%E0%AF%81%E0%AE%9F%E0%AE%BF%E0%AE%AF%E0%AF%81%E0%AE%AE%E0%AF%8D.+%E0%AE%85%E0%AE%A4%E0%AF%81+%E0%AE%9A%E0%AE%BF%E0%AE%B2+%E0%AE%A8%E0%AE%A9%E0%AF%8D%E0%AE%AE%E0%AF%88%E0%AE%95%E0%AE%B3%E0%AF%88+%E0%AE%AA%E0%AF%86%E0%AE%B1+%E0%AE%A4%E0%AE%B5%E0%AE%BF%E0%AE%B0%2C+%E0%AE%8E%E0%AE%AA%E0%AF%8D%E0%AE%AA%E0%AF%87%E0%AE%BE%E0%AE%A4%E0%AF%81%E0%AE%AE%E0%AF%8D+%E0%AE%89%E0%AE%B4%E0%AF%88%E0%AE%95%E0%AF%8D%E0%AE%95+%E0%AE%89%E0%AE%9F%E0%AE%B1%E0%AF%8D%E0%AE%AA%E0%AE%AF%E0%AE%BF%E0%AE%B1%E0%AF%8D%E0%AE%9A%E0%AE%BF+%E0%AE%AE%E0%AF%87%E0%AE%B1%E0%AF%8D%E0%AE%95%E0%AF%86%E0%AE%BE%E0%AE%B3%E0%AF%8D%E0%AE%95%E0%AE%BF%E0%AE%B1%E0%AE%A4%E0%AF%81+%E0%AE%8E%E0%AE%99%E0%AF%8D%E0%AE%95%E0%AE%B3%E0%AF%81%E0%AE%95%E0%AF%8D%E0%AE%95%E0%AF%81+%E0%AE%87%E0%AE%A4%E0%AF%81+%E0%AE%92%E0%AE%B0%E0%AF%81+%E0%AE%9A%E0%AE%BF%E0%AE%B1%E0%AE%BF%E0%AE%AF+%E0%AE%89%E0%AE%A4%E0%AE%BE%E0%AE%B0%E0%AE%A3%E0%AE%AE%E0%AF%8D%2C+%E0%AE%8E%E0%AE%9F%E0%AF%81%E0%AE%95%E0%AF%8D%E0%AE%95.+%E0%AE%B0%E0%AE%AF%E0%AE%BF%E0%AE%B2%E0%AF%8D+%E0%AE%8E%E0%AE%A8%E0%AF%8D%E0%AE%A4+%E0%AE%B5%E0%AE%BF%E0%AE%B3%E0%AF%88%E0%AE%B5%E0%AE%BE%E0%AE%95+%E0%AE%87%E0%AE%A9%E0%AF%8D%E0%AE%AA%E0%AE%AE%E0%AF%8D+%E0%AE%86%E0%AE%A9%E0%AF%8D%E0%AE%B2%E0%AF%88%E0%AE%A9%E0%AF%8D+%E0%AE%AA%E0%AE%AF%E0%AE%A9%E0%AF%8D%E0%AE%AA%E0%AE%BE%E0%AE%9F%E0%AF%81%E0%AE%95%E0%AE%B3%E0%AF%8D+%E0%AE%87%E0%AE%B0%E0%AF%81%E0%AE%95%E0%AF%8D%E0%AE%95+%E0%AE%B5%E0%AF%87%E0%AE%A3%E0%AF%8D%E0%AE%9F%E0%AF%81%E0%AE%AE%E0%AF%8D+%E0%AE%A4%E0%AE%AF%E0%AE%BE%E0%AE%B0%E0%AE%BF%E0%AE%95%E0%AF%8D%E0%AE%95%E0%AF%81%E0%AE%AE%E0%AF%8D+%E0%AE%A4%E0%AE%B5%E0%AE%B1%E0%AF%81+%E0%AE%95%E0%AE%A3%E0%AF%8D%E0%AE%9F%E0%AF%81%E0%AE%AA%E0%AE%BF%E0%AE%9F%E0%AE%BF%E0%AE%95%E0%AF%8D%E0%AE%95+%E0%AE%B5%E0%AE%B0%E0%AF%81%E0%AE%AE%E0%AF%8D+%E0%AE%A8%E0%AE%BE%E0%AE%AE%E0%AF%8D+%E0%AE%A4%E0%AE%B1%E0%AF%8D%E0%AE%AA%E0%AF%87%E0%AE%BE%E0%AE%A4%E0%AF%81+%E0%AE%87%E0%AE%B0%E0%AF%81%E0%AE%95%E0%AF%8D%E0%AE%95%E0%AE%BF%E0%AE%B1%E0%AF%87%E0%AE%BE%E0%AE%AE%E0%AF%8D.+%E0%AE%87%E0%AE%A8%E0%AF%8D%E0%AE%A4+%E0%AE%A8%E0%AE%BF%E0%AE%95%E0%AE%B4%E0%AF%8D%E0%AE%B5%E0%AF%81%E0%AE%95%E0%AE%B3%E0%AE%BF%E0%AE%B2%E0%AF%8D+%E0%AE%9A%E0%AF%86%E0%AE%AF%E0%AF%8D%E0%AE%A4%E0%AE%AA%E0%AE%BF%E0%AE%A9%E0%AF%8D+%E0%AE%85%E0%AE%AE%E0%AF%88%E0%AE%AA%E0%AF%8D%E0%AE%AA%E0%AE%BF%E0%AE%A9%E0%AF%8D+%E0%AE%95%E0%AE%A3%E0%AE%95%E0%AF%8D%E0%AE%95%E0%AF%81%2C+%E0%AE%85%E0%AE%B5%E0%AE%B0%E0%AF%8D%E0%AE%95%E0%AE%B3%E0%AF%8D+%E0%AE%A4%E0%AE%B5%E0%AE%B1%E0%AF%81+%E0%AE%B5%E0%AE%BF%E0%AE%9F%E0%AF%8D%E0%AE%9F%E0%AF%81+quae+%E0%AE%AA%E0%AE%9F%E0%AF%8D%E0%AE%9F%E0%AE%B1%E0%AF%88+%E0%AE%A8%E0%AF%80%E0%AE%99%E0%AF%8D%E0%AE%95%E0%AE%B3%E0%AF%8D+%E0%AE%AA%E0%AE%B0%E0%AE%BF%E0%AE%A8%E0%AF%8D%E0%AE%A4%E0%AF%81%E0%AE%B0%E0%AF%88%E0%AE%95%E0%AF%8D%E0%AE%95%E0%AE%BF%E0%AE%B1%E0%AF%87%E0%AE%BE%E0%AE%AE%E0%AF%8D+%E0%AE%AE%E0%AF%86%E0%AE%A9%E0%AF%8D%E0%AE%AE%E0%AF%88%E0%AE%AF%E0%AE%BE%E0%AE%95+%E0%AE%AE%E0%AE%BE%E0%AE%B1%E0%AF%81%E0%AE%AE%E0%AF%8D"; - @Parameterized.Parameters(name = "mType({0})") - public static Collection cases() { + public static Collection getCases() { final List<Object[]> params = new ArrayList<>(); for (Type type : Type.values()) { - params.add(new Object[]{type}); + params.add(new Object[] {type}); } return params; } - @Parameterized.Parameter(0) - public Type mType; - Object mA1; Object mA2; Object mB1; @@ -73,20 +74,13 @@ public final class EqualsHashCodePerfTest { Object mC1; Object mC2; - @Before - public void setUp() throws Exception { - mA1 = mType.newInstance("https://mail.google.com/mail/u/0/?shva=1#inbox"); - mA2 = mType.newInstance("https://mail.google.com/mail/u/0/?shva=1#inbox"); - mB1 = mType.newInstance("http://developer.android.com/reference/java/net/URI.html"); - mB2 = mType.newInstance("http://developer.android.com/reference/java/net/URI.html"); - - mC1 = mType.newInstance("http://developer.android.com/query?q=" + QUERY); - // Replace the very last char. - mC2 = mType.newInstance("http://developer.android.com/query?q=" + QUERY.substring(0, QUERY.length() - 3) + "%AF"); - } - @Test - public void timeEquals() { + @Parameters(method = "getCases") + public void timeEquals(Type type) throws Exception { + mA1 = type.newInstance("https://mail.google.com/mail/u/0/?shva=1#inbox"); + 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"); BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { mA1.equals(mB1); @@ -96,7 +90,10 @@ public final class EqualsHashCodePerfTest { } @Test - public void timeHashCode() { + @Parameters(method = "getCases") + 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"); BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { mA1.hashCode(); @@ -105,7 +102,15 @@ public final class EqualsHashCodePerfTest { } @Test - public void timeEqualsWithHeavilyEscapedComponent() { + @Parameters(method = "getCases") + public void timeEqualsWithHeavilyEscapedComponent(Type type) throws Exception { + mC1 = type.newInstance("http://developer.android.com/query?q=" + QUERY); + // Replace the very last char. + mC2 = + type.newInstance( + "http://developer.android.com/query?q=" + + QUERY.substring(0, QUERY.length() - 3) + + "%AF"); BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { mC1.equals(mC2); 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 6fe9059cb3de..80c448732b59 100644 --- a/apct-tests/perftests/core/src/android/libcore/regression/KeyPairGeneratorPerfTest.java +++ b/apct-tests/perftests/core/src/android/libcore/regression/KeyPairGeneratorPerfTest.java @@ -20,26 +20,24 @@ import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; import android.test.suitebuilder.annotation.LargeTest; -import org.junit.Before; +import junitparams.JUnitParamsRunner; +import junitparams.Parameters; + import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; import java.security.KeyPair; import java.security.KeyPairGenerator; -import java.security.SecureRandom; import java.util.Arrays; import java.util.Collection; -@RunWith(Parameterized.class) +@RunWith(JUnitParamsRunner.class) @LargeTest public class KeyPairGeneratorPerfTest { @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter(); - @Parameters(name = "mAlgorithm={0}, mImplementation={1}") - public static Collection<Object[]> data() { + public static Collection<Object[]> getData() { return Arrays.asList( new Object[][] { {Algorithm.RSA, Implementation.BouncyCastle}, @@ -48,12 +46,6 @@ public class KeyPairGeneratorPerfTest { }); } - @Parameterized.Parameter(0) - public Algorithm mAlgorithm; - - @Parameterized.Parameter(1) - public Implementation mImplementation; - public enum Algorithm { RSA, DSA, @@ -66,26 +58,25 @@ public class KeyPairGeneratorPerfTest { private String mGeneratorAlgorithm; private KeyPairGenerator mGenerator; - private SecureRandom mRandom; - @Before - public void setUp() throws Exception { - this.mGeneratorAlgorithm = mAlgorithm.toString(); + public void setUp(Algorithm algorithm, Implementation implementation) throws Exception { + this.mGeneratorAlgorithm = algorithm.toString(); final String provider; - if (mImplementation == Implementation.BouncyCastle) { + if (implementation == Implementation.BouncyCastle) { provider = "BC"; } else { provider = "AndroidOpenSSL"; } this.mGenerator = KeyPairGenerator.getInstance(mGeneratorAlgorithm, provider); - this.mRandom = SecureRandom.getInstance("SHA1PRNG"); this.mGenerator.initialize(1024); } @Test - public void time() throws Exception { + @Parameters(method = "getData") + public void time(Algorithm algorithm, Implementation implementation) throws Exception { + setUp(algorithm, implementation); 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 414764d292b8..c9b0cbe1bedb 100644 --- a/apct-tests/perftests/core/src/android/libcore/regression/LoopingBackwardsPerfTest.java +++ b/apct-tests/perftests/core/src/android/libcore/regression/LoopingBackwardsPerfTest.java @@ -20,11 +20,12 @@ import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; import android.test.suitebuilder.annotation.LargeTest; +import junitparams.JUnitParamsRunner; +import junitparams.Parameters; + import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; import java.util.Arrays; import java.util.Collection; @@ -34,36 +35,34 @@ import java.util.Collection; * * @author Kevin Bourrillion */ -@RunWith(Parameterized.class) +@RunWith(JUnitParamsRunner.class) @LargeTest public class LoopingBackwardsPerfTest { @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter(); - @Parameters(name = "mMax={0}") - public static Collection<Object[]> data() { + public static Collection<Object[]> getData() { return Arrays.asList(new Object[][] {{2}, {20}, {2000}, {20000000}}); } - @Parameterized.Parameter(0) - public int mMax; - @Test - public void timeForwards() { + @Parameters(method = "getData") + public void timeForwards(int max) { int fake = 0; BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { - for (int j = 0; j < mMax; j++) { + for (int j = 0; j < max; j++) { fake += j; } } } @Test - public void timeBackwards() { + @Parameters(method = "getData") + public void timeBackwards(int max) { int fake = 0; BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { - for (int j = mMax - 1; j >= 0; j--) { + for (int j = max - 1; j >= 0; j--) { fake += j; } } 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 279681bc0d15..2dc947a613d2 100644 --- a/apct-tests/perftests/core/src/android/libcore/regression/MessageDigestPerfTest.java +++ b/apct-tests/perftests/core/src/android/libcore/regression/MessageDigestPerfTest.java @@ -20,24 +20,24 @@ import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; import android.test.suitebuilder.annotation.LargeTest; +import junitparams.JUnitParamsRunner; +import junitparams.Parameters; + import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; import java.nio.ByteBuffer; import java.security.MessageDigest; import java.util.Arrays; import java.util.Collection; -@RunWith(Parameterized.class) +@RunWith(JUnitParamsRunner.class) @LargeTest public class MessageDigestPerfTest { @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter(); - @Parameters(name = "mAlgorithm={0}") - public static Collection<Object[]> data() { + public static Collection<Object[]> getData() { return Arrays.asList( new Object[][] { {Algorithm.MD5}, @@ -48,9 +48,6 @@ public class MessageDigestPerfTest { }); } - @Parameterized.Parameter(0) - public Algorithm mAlgorithm; - public String mProvider = "AndroidOpenSSL"; private static final int DATA_SIZE = 8192; @@ -97,44 +94,44 @@ public class MessageDigestPerfTest { }; @Test - public void time() throws Exception { + @Parameters(method = "getData") + public void time(Algorithm algorithm) throws Exception { BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { - MessageDigest digest = - MessageDigest.getInstance(mAlgorithm.toString(), mProvider); + MessageDigest digest = MessageDigest.getInstance(algorithm.toString(), mProvider); digest.update(DATA, 0, DATA_SIZE); digest.digest(); } } @Test - public void timeLargeArray() throws Exception { + @Parameters(method = "getData") + public void timeLargeArray(Algorithm algorithm) throws Exception { BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { - MessageDigest digest = - MessageDigest.getInstance(mAlgorithm.toString(), mProvider); + MessageDigest digest = MessageDigest.getInstance(algorithm.toString(), mProvider); digest.update(LARGE_DATA, 0, LARGE_DATA_SIZE); digest.digest(); } } @Test - public void timeSmallChunkOfLargeArray() throws Exception { + @Parameters(method = "getData") + public void timeSmallChunkOfLargeArray(Algorithm algorithm) throws Exception { BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { - MessageDigest digest = - MessageDigest.getInstance(mAlgorithm.toString(), mProvider); + MessageDigest digest = MessageDigest.getInstance(algorithm.toString(), mProvider); digest.update(LARGE_DATA, LARGE_DATA_SIZE / 2, DATA_SIZE); digest.digest(); } } @Test - public void timeSmallByteBuffer() throws Exception { + @Parameters(method = "getData") + public void timeSmallByteBuffer(Algorithm algorithm) throws Exception { BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { - MessageDigest digest = - MessageDigest.getInstance(mAlgorithm.toString(), mProvider); + MessageDigest digest = MessageDigest.getInstance(algorithm.toString(), mProvider); SMALL_BUFFER.position(0); SMALL_BUFFER.limit(SMALL_BUFFER.capacity()); digest.update(SMALL_BUFFER); @@ -143,11 +140,11 @@ public class MessageDigestPerfTest { } @Test - public void timeSmallDirectByteBuffer() throws Exception { + @Parameters(method = "getData") + public void timeSmallDirectByteBuffer(Algorithm algorithm) throws Exception { BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { - MessageDigest digest = - MessageDigest.getInstance(mAlgorithm.toString(), mProvider); + MessageDigest digest = MessageDigest.getInstance(algorithm.toString(), mProvider); SMALL_DIRECT_BUFFER.position(0); SMALL_DIRECT_BUFFER.limit(SMALL_DIRECT_BUFFER.capacity()); digest.update(SMALL_DIRECT_BUFFER); @@ -156,11 +153,11 @@ public class MessageDigestPerfTest { } @Test - public void timeLargeByteBuffer() throws Exception { + @Parameters(method = "getData") + public void timeLargeByteBuffer(Algorithm algorithm) throws Exception { BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { - MessageDigest digest = - MessageDigest.getInstance(mAlgorithm.toString(), mProvider); + MessageDigest digest = MessageDigest.getInstance(algorithm.toString(), mProvider); LARGE_BUFFER.position(0); LARGE_BUFFER.limit(LARGE_BUFFER.capacity()); digest.update(LARGE_BUFFER); @@ -169,11 +166,11 @@ public class MessageDigestPerfTest { } @Test - public void timeLargeDirectByteBuffer() throws Exception { + @Parameters(method = "getData") + public void timeLargeDirectByteBuffer(Algorithm algorithm) throws Exception { BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { - MessageDigest digest = - MessageDigest.getInstance(mAlgorithm.toString(), mProvider); + MessageDigest digest = MessageDigest.getInstance(algorithm.toString(), mProvider); LARGE_DIRECT_BUFFER.position(0); LARGE_DIRECT_BUFFER.limit(LARGE_DIRECT_BUFFER.capacity()); digest.update(LARGE_DIRECT_BUFFER); @@ -182,11 +179,11 @@ public class MessageDigestPerfTest { } @Test - public void timeSmallChunkOfLargeByteBuffer() throws Exception { + @Parameters(method = "getData") + public void timeSmallChunkOfLargeByteBuffer(Algorithm algorithm) throws Exception { BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { - MessageDigest digest = - MessageDigest.getInstance(mAlgorithm.toString(), mProvider); + MessageDigest digest = MessageDigest.getInstance(algorithm.toString(), mProvider); LARGE_BUFFER.position(LARGE_BUFFER.capacity() / 2); LARGE_BUFFER.limit(LARGE_BUFFER.position() + DATA_SIZE); digest.update(LARGE_BUFFER); @@ -195,11 +192,11 @@ public class MessageDigestPerfTest { } @Test - public void timeSmallChunkOfLargeDirectByteBuffer() throws Exception { + @Parameters(method = "getData") + public void timeSmallChunkOfLargeDirectByteBuffer(Algorithm algorithm) throws Exception { BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { - MessageDigest digest = - MessageDigest.getInstance(mAlgorithm.toString(), mProvider); + MessageDigest digest = MessageDigest.getInstance(algorithm.toString(), mProvider); LARGE_DIRECT_BUFFER.position(LARGE_DIRECT_BUFFER.capacity() / 2); LARGE_DIRECT_BUFFER.limit(LARGE_DIRECT_BUFFER.position() + DATA_SIZE); digest.update(LARGE_DIRECT_BUFFER); 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 37bd73c8731a..d9d4bb5d0ae1 100644 --- a/apct-tests/perftests/core/src/android/libcore/regression/MutableIntPerfTest.java +++ b/apct-tests/perftests/core/src/android/libcore/regression/MutableIntPerfTest.java @@ -20,17 +20,18 @@ import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; import android.test.suitebuilder.annotation.LargeTest; +import junitparams.JUnitParamsRunner; +import junitparams.Parameters; + import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; import java.util.Arrays; import java.util.Collection; import java.util.concurrent.atomic.AtomicInteger; -@RunWith(Parameterized.class) +@RunWith(JUnitParamsRunner.class) @LargeTest public final class MutableIntPerfTest { @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter(); @@ -96,29 +97,28 @@ public final class MutableIntPerfTest { abstract int timeGet(BenchmarkState state); } - @Parameters(name = "mKind={0}") - public static Collection<Object[]> data() { + public static Collection<Object[]> getData() { return Arrays.asList(new Object[][] {{Kind.ARRAY}, {Kind.ATOMIC}}); } - @Parameterized.Parameter(0) - public Kind mKind; - @Test - public void timeCreate() { + @Parameters(method = "getData") + public void timeCreate(Kind kind) { BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); - mKind.timeCreate(state); + kind.timeCreate(state); } @Test - public void timeIncrement() { + @Parameters(method = "getData") + public void timeIncrement(Kind kind) { BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); - mKind.timeIncrement(state); + kind.timeIncrement(state); } @Test - public void timeGet() { + @Parameters(method = "getData") + public void timeGet(Kind kind) { BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); - mKind.timeGet(state); + kind.timeGet(state); } } 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 8801a5690cb2..48450b4616e6 100644 --- a/apct-tests/perftests/core/src/android/libcore/regression/PriorityQueuePerfTest.java +++ b/apct-tests/perftests/core/src/android/libcore/regression/PriorityQueuePerfTest.java @@ -20,12 +20,12 @@ import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; import android.test.suitebuilder.annotation.LargeTest; -import org.junit.Before; +import junitparams.JUnitParamsRunner; +import junitparams.Parameters; + import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; import java.util.ArrayList; import java.util.Arrays; @@ -35,13 +35,12 @@ import java.util.List; import java.util.PriorityQueue; import java.util.Random; -@RunWith(Parameterized.class) +@RunWith(JUnitParamsRunner.class) @LargeTest public class PriorityQueuePerfTest { @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter(); - @Parameters(name = "mQueueSize={0}, mHitRate={1}") - public static Collection<Object[]> data() { + public static Collection<Object[]> getData() { return Arrays.asList( new Object[][] { {100, 0}, @@ -62,26 +61,19 @@ public class PriorityQueuePerfTest { }); } - @Parameterized.Parameter(0) - public int mQueueSize; - - @Parameterized.Parameter(1) - public int mHitRate; - private PriorityQueue<Integer> mPq; private PriorityQueue<Integer> mUsepq; private List<Integer> mSeekElements; private Random mRandom = new Random(189279387L); - @Before - public void setUp() throws Exception { + public void setUp(int queueSize, int hitRate) throws Exception { mPq = new PriorityQueue<Integer>(); mUsepq = new PriorityQueue<Integer>(); mSeekElements = new ArrayList<Integer>(); List<Integer> allElements = new ArrayList<Integer>(); - int numShared = (int) (mQueueSize * ((double) mHitRate / 100)); - // the total number of elements we require to engineer a hit rate of mHitRate% - int totalElements = 2 * mQueueSize - numShared; + int numShared = (int) (queueSize * ((double) hitRate / 100)); + // the total number of elements we require to engineer a hit rate of hitRate% + int totalElements = 2 * queueSize - numShared; for (int i = 0; i < totalElements; i++) { allElements.add(i); } @@ -93,11 +85,11 @@ public class PriorityQueuePerfTest { mSeekElements.add(allElements.get(i)); } // add priority queue only elements (these won't be touched) - for (int i = numShared; i < mQueueSize; i++) { + for (int i = numShared; i < queueSize; i++) { mPq.add(allElements.get(i)); } // add non-priority queue elements (these will be misses) - for (int i = mQueueSize; i < totalElements; i++) { + for (int i = queueSize; i < totalElements; i++) { mSeekElements.add(allElements.get(i)); } mUsepq = new PriorityQueue<Integer>(mPq); @@ -107,16 +99,18 @@ public class PriorityQueuePerfTest { } @Test - public void timeRemove() { + @Parameters(method = "getData") + public void timeRemove(int queueSize, int hitRate) throws Exception { + setUp(queueSize, hitRate); boolean fake = false; int elementsSize = mSeekElements.size(); // At most allow the queue to empty 10%. - int resizingThreshold = mQueueSize / 10; + int resizingThreshold = queueSize / 10; int i = 0; BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { // Reset queue every so often. This will be called more often for smaller - // mQueueSizes, but since a copy is linear, it will also cost proportionally + // queueSizes, but since a copy is linear, it will also cost proportionally // less, and hopefully it will approximately balance out. if (++i % resizingThreshold == 0) { mUsepq = new PriorityQueue<Integer>(mPq); 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 42dc5811e6db..5ad62dedcae7 100644 --- a/apct-tests/perftests/core/src/android/libcore/regression/SchemePrefixPerfTest.java +++ b/apct-tests/perftests/core/src/android/libcore/regression/SchemePrefixPerfTest.java @@ -20,11 +20,12 @@ import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; import android.test.suitebuilder.annotation.LargeTest; +import junitparams.JUnitParamsRunner; +import junitparams.Parameters; + import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; import java.util.Arrays; import java.util.Collection; @@ -32,7 +33,7 @@ import java.util.Locale; import java.util.regex.Matcher; import java.util.regex.Pattern; -@RunWith(Parameterized.class) +@RunWith(JUnitParamsRunner.class) @LargeTest public final class SchemePrefixPerfTest { @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter(); @@ -85,19 +86,16 @@ public final class SchemePrefixPerfTest { abstract String execute(String spec); } - @Parameters(name = "mStrategy={0}") - public static Collection<Object[]> data() { + public static Collection<Object[]> getData() { return Arrays.asList(new Object[][] {{Strategy.REGEX}, {Strategy.JAVA}}); } - @Parameterized.Parameter(0) - public Strategy mStrategy; - @Test - public void timeSchemePrefix() { + @Parameters(method = "getData") + public void timeSchemePrefix(Strategy strategy) { BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { - mStrategy.execute("http://android.com"); + strategy.execute("http://android.com"); } } } 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 96e7cb27afef..a9a0788f6136 100644 --- a/apct-tests/perftests/core/src/android/libcore/regression/SignaturePerfTest.java +++ b/apct-tests/perftests/core/src/android/libcore/regression/SignaturePerfTest.java @@ -19,12 +19,12 @@ import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; import android.test.suitebuilder.annotation.LargeTest; -import org.junit.Before; +import junitparams.JUnitParamsRunner; +import junitparams.Parameters; + import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; import java.security.KeyPair; import java.security.KeyPairGenerator; @@ -37,13 +37,12 @@ import java.util.HashMap; import java.util.Map; /** Tests RSA and DSA mSignature creation and verification. */ -@RunWith(Parameterized.class) +@RunWith(JUnitParamsRunner.class) @LargeTest public class SignaturePerfTest { @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter(); - @Parameters(name = "mAlgorithm={0}, mImplementation={1}") - public static Collection<Object[]> data() { + public static Collection<Object[]> getData() { return Arrays.asList( new Object[][] { {Algorithm.MD5WithRSA, Implementation.OpenSSL}, @@ -55,12 +54,6 @@ public class SignaturePerfTest { }); } - @Parameterized.Parameter(0) - public Algorithm mAlgorithm; - - @Parameterized.Parameter(1) - public Implementation mImplementation; - private static final int DATA_SIZE = 8192; private static final byte[] DATA = new byte[DATA_SIZE]; @@ -94,9 +87,8 @@ public class SignaturePerfTest { private PrivateKey mPrivateKey; private PublicKey mPublicKey; - @Before - public void setUp() throws Exception { - this.mSignatureAlgorithm = mAlgorithm.toString(); + public void setUp(Algorithm algorithm) throws Exception { + this.mSignatureAlgorithm = algorithm.toString(); String keyAlgorithm = mSignatureAlgorithm.substring( @@ -121,11 +113,13 @@ public class SignaturePerfTest { } @Test - public void timeSign() throws Exception { + @Parameters(method = "getData") + public void timeSign(Algorithm algorithm, Implementation implementation) throws Exception { + setUp(algorithm); BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { Signature signer; - switch (mImplementation) { + switch (implementation) { case OpenSSL: signer = Signature.getInstance(mSignatureAlgorithm, "AndroidOpenSSL"); break; @@ -133,7 +127,7 @@ public class SignaturePerfTest { signer = Signature.getInstance(mSignatureAlgorithm, "BC"); break; default: - throw new RuntimeException(mImplementation.toString()); + throw new RuntimeException(implementation.toString()); } signer.initSign(mPrivateKey); signer.update(DATA); @@ -142,11 +136,13 @@ public class SignaturePerfTest { } @Test - public void timeVerify() throws Exception { + @Parameters(method = "getData") + public void timeVerify(Algorithm algorithm, Implementation implementation) throws Exception { + setUp(algorithm); BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { Signature verifier; - switch (mImplementation) { + switch (implementation) { case OpenSSL: verifier = Signature.getInstance(mSignatureAlgorithm, "AndroidOpenSSL"); break; @@ -154,7 +150,7 @@ public class SignaturePerfTest { verifier = Signature.getInstance(mSignatureAlgorithm, "BC"); break; default: - throw new RuntimeException(mImplementation.toString()); + throw new RuntimeException(implementation.toString()); } verifier.initVerify(mPublicKey); verifier.update(DATA); 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 02194b1b9745..36db014b75a5 100644 --- a/apct-tests/perftests/core/src/android/libcore/regression/StringPerfTest.java +++ b/apct-tests/perftests/core/src/android/libcore/regression/StringPerfTest.java @@ -20,16 +20,17 @@ import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; import android.test.suitebuilder.annotation.LargeTest; +import junitparams.JUnitParamsRunner; +import junitparams.Parameters; + import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; import java.util.Arrays; import java.util.Collection; -@RunWith(Parameterized.class) +@RunWith(JUnitParamsRunner.class) @LargeTest public class StringPerfTest { @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter(); @@ -46,8 +47,7 @@ public class StringPerfTest { } } - @Parameters(name = "mStringLengths={0}") - public static Collection<Object[]> data() { + public static Collection<Object[]> getData() { return Arrays.asList( new Object[][] { {StringLengths.EIGHT_KI}, @@ -57,9 +57,6 @@ public class StringPerfTest { }); } - @Parameterized.Parameter(0) - public StringLengths mStringLengths; - private static String makeString(int length) { StringBuilder result = new StringBuilder(length); for (int i = 0; i < length; ++i) { @@ -69,10 +66,11 @@ public class StringPerfTest { } @Test - public void timeHashCode() { + @Parameters(method = "getData") + public void timeHashCode(StringLengths stringLengths) { BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { - mStringLengths.mValue.hashCode(); + 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 b0d1ee4132fa..5b4423a32831 100644 --- a/apct-tests/perftests/core/src/android/libcore/regression/StringReplaceAllPerfTest.java +++ b/apct-tests/perftests/core/src/android/libcore/regression/StringReplaceAllPerfTest.java @@ -20,16 +20,17 @@ import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; import android.test.suitebuilder.annotation.LargeTest; +import junitparams.JUnitParamsRunner; +import junitparams.Parameters; + import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; import java.util.Arrays; import java.util.Collection; -@RunWith(Parameterized.class) +@RunWith(JUnitParamsRunner.class) @LargeTest public class StringReplaceAllPerfTest { @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter(); @@ -69,8 +70,7 @@ public class StringReplaceAllPerfTest { return stringBuilder.toString(); } - @Parameters(name = "mStringLengths={0}") - public static Collection<Object[]> data() { + public static Collection<Object[]> getData() { return Arrays.asList( new Object[][] { {StringLengths.BOOT_IMAGE}, @@ -82,30 +82,30 @@ public class StringReplaceAllPerfTest { }); } - @Parameterized.Parameter(0) - public StringLengths mStringLengths; - @Test - public void timeReplaceAllTrivialPatternNonExistent() { + @Parameters(method = "getData") + public void timeReplaceAllTrivialPatternNonExistent(StringLengths stringLengths) { BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { - mStringLengths.mValue.replaceAll("fish", "0"); + stringLengths.mValue.replaceAll("fish", "0"); } } @Test - public void timeReplaceTrivialPatternAllRepeated() { + @Parameters(method = "getData") + public void timeReplaceTrivialPatternAllRepeated(StringLengths stringLengths) { BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { - mStringLengths.mValue.replaceAll("jklm", "0"); + stringLengths.mValue.replaceAll("jklm", "0"); } } @Test - public void timeReplaceAllTrivialPatternSingleOccurrence() { + @Parameters(method = "getData") + public void timeReplaceAllTrivialPatternSingleOccurrence(StringLengths stringLengths) { BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { - mStringLengths.mValue.replaceAll("qrst", "0"); + 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 d2e657a78608..4d5c792295b9 100644 --- a/apct-tests/perftests/core/src/android/libcore/regression/StringReplacePerfTest.java +++ b/apct-tests/perftests/core/src/android/libcore/regression/StringReplacePerfTest.java @@ -20,16 +20,17 @@ import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; import android.test.suitebuilder.annotation.LargeTest; +import junitparams.JUnitParamsRunner; +import junitparams.Parameters; + import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; import java.util.Arrays; import java.util.Collection; -@RunWith(Parameterized.class) +@RunWith(JUnitParamsRunner.class) @LargeTest public class StringReplacePerfTest { @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter(); @@ -64,8 +65,7 @@ public class StringReplacePerfTest { return stringBuilder.toString(); } - @Parameters(name = "mStringLengths={0}") - public static Collection<Object[]> data() { + public static Collection<Object[]> getData() { return Arrays.asList( new Object[][] { {StringLengths.EMPTY}, @@ -76,54 +76,57 @@ public class StringReplacePerfTest { }); } - @Parameterized.Parameter(0) - public StringLengths mStringLengths; - @Test - public void timeReplaceCharNonExistent() { + @Parameters(method = "getData") + public void timeReplaceCharNonExistent(StringLengths stringLengths) { BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { - mStringLengths.mValue.replace('z', '0'); + stringLengths.mValue.replace('z', '0'); } } @Test - public void timeReplaceCharRepeated() { + @Parameters(method = "getData") + public void timeReplaceCharRepeated(StringLengths stringLengths) { BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { - mStringLengths.mValue.replace('a', '0'); + stringLengths.mValue.replace('a', '0'); } } @Test - public void timeReplaceSingleChar() { + @Parameters(method = "getData") + public void timeReplaceSingleChar(StringLengths stringLengths) { BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { - mStringLengths.mValue.replace('q', '0'); + stringLengths.mValue.replace('q', '0'); } } @Test - public void timeReplaceSequenceNonExistent() { + @Parameters(method = "getData") + public void timeReplaceSequenceNonExistent(StringLengths stringLengths) { BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { - mStringLengths.mValue.replace("fish", "0"); + stringLengths.mValue.replace("fish", "0"); } } @Test - public void timeReplaceSequenceRepeated() { + @Parameters(method = "getData") + public void timeReplaceSequenceRepeated(StringLengths stringLengths) { BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { - mStringLengths.mValue.replace("jklm", "0"); + stringLengths.mValue.replace("jklm", "0"); } } @Test - public void timeReplaceSingleSequence() { + @Parameters(method = "getData") + public void timeReplaceSingleSequence(StringLengths stringLengths) { BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { - mStringLengths.mValue.replace("qrst", "0"); + stringLengths.mValue.replace("qrst", "0"); } } } 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 1efc188f4e4d..c004d959b9b3 100644 --- a/apct-tests/perftests/core/src/android/libcore/regression/StringToBytesPerfTest.java +++ b/apct-tests/perftests/core/src/android/libcore/regression/StringToBytesPerfTest.java @@ -20,17 +20,18 @@ import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; import android.test.suitebuilder.annotation.LargeTest; +import junitparams.JUnitParamsRunner; +import junitparams.Parameters; + import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.Collection; -@RunWith(Parameterized.class) +@RunWith(JUnitParamsRunner.class) @LargeTest public class StringToBytesPerfTest { @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter(); @@ -53,8 +54,7 @@ public class StringToBytesPerfTest { } } - @Parameters(name = "mStringLengths={0}") - public static Collection<Object[]> data() { + public static Collection<Object[]> getData() { return Arrays.asList( new Object[][] { {StringLengths.EMPTY}, @@ -69,9 +69,6 @@ public class StringToBytesPerfTest { }); } - @Parameterized.Parameter(0) - public StringLengths mStringLengths; - private static String makeString(int length) { char[] chars = new char[length]; for (int i = 0; i < length; ++i) { @@ -89,26 +86,29 @@ public class StringToBytesPerfTest { } @Test - public void timeGetBytesUtf8() { + @Parameters(method = "getData") + public void timeGetBytesUtf8(StringLengths stringLengths) { BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { - mStringLengths.mValue.getBytes(StandardCharsets.UTF_8); + stringLengths.mValue.getBytes(StandardCharsets.UTF_8); } } @Test - public void timeGetBytesIso88591() { + @Parameters(method = "getData") + public void timeGetBytesIso88591(StringLengths stringLengths) { BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { - mStringLengths.mValue.getBytes(StandardCharsets.ISO_8859_1); + stringLengths.mValue.getBytes(StandardCharsets.ISO_8859_1); } } @Test - public void timeGetBytesAscii() { + @Parameters(method = "getData") + public void timeGetBytesAscii(StringLengths stringLengths) { BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { - mStringLengths.mValue.getBytes(StandardCharsets.US_ASCII); + 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 b01948aa2255..15516fc1c51c 100644 --- a/apct-tests/perftests/core/src/android/libcore/regression/StringToRealPerfTest.java +++ b/apct-tests/perftests/core/src/android/libcore/regression/StringToRealPerfTest.java @@ -20,22 +20,22 @@ import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; import android.test.suitebuilder.annotation.LargeTest; +import junitparams.JUnitParamsRunner; +import junitparams.Parameters; + import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; import java.util.Arrays; import java.util.Collection; -@RunWith(Parameterized.class) +@RunWith(JUnitParamsRunner.class) @LargeTest public class StringToRealPerfTest { @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter(); - @Parameters(name = "mString={0}") - public static Collection<Object[]> data() { + public static Collection<Object[]> getData() { return Arrays.asList( new Object[][] { {"NaN"}, @@ -49,22 +49,21 @@ public class StringToRealPerfTest { }); } - @Parameterized.Parameter(0) - public String mString; - @Test - public void timeFloat_parseFloat() { + @Parameters(method = "getData") + public void timeFloat_parseFloat(String string) { BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { - Float.parseFloat(mString); + Float.parseFloat(string); } } @Test - public void timeDouble_parseDouble() { + @Parameters(method = "getData") + public void timeDouble_parseDouble(String string) { BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { - Double.parseDouble(mString); + Double.parseDouble(string); } } } 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 2ea834d0b71c..ae1e8bce42ac 100644 --- a/apct-tests/perftests/core/src/android/libcore/regression/XMLEntitiesPerfTest.java +++ b/apct-tests/perftests/core/src/android/libcore/regression/XMLEntitiesPerfTest.java @@ -20,12 +20,12 @@ import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; import android.test.suitebuilder.annotation.LargeTest; -import org.junit.Before; +import junitparams.JUnitParamsRunner; +import junitparams.Parameters; + import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; import org.xml.sax.InputSource; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserFactory; @@ -38,13 +38,12 @@ import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; // http://code.google.com/p/android/issues/detail?id=18102 -@RunWith(Parameterized.class) +@RunWith(JUnitParamsRunner.class) @LargeTest public final class XMLEntitiesPerfTest { @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter(); - @Parameters(name = "mLength={0}, mEntityFraction={1}") - public static Collection<Object[]> data() { + public static Collection<Object[]> getData() { return Arrays.asList( new Object[][] { {10, 0}, @@ -59,29 +58,22 @@ public final class XMLEntitiesPerfTest { }); } - @Parameterized.Parameter(0) - public int mLength; - - @Parameterized.Parameter(1) - public float mEntityFraction; - private XmlPullParserFactory mXmlPullParserFactory; private DocumentBuilderFactory mDocumentBuilderFactory; /** a string like {@code <doc>&&++</doc>}. */ private String mXml; - @Before - public void setUp() throws Exception { + public void setUp(int length, float entityFraction) throws Exception { mXmlPullParserFactory = XmlPullParserFactory.newInstance(); mDocumentBuilderFactory = DocumentBuilderFactory.newInstance(); StringBuilder xmlBuilder = new StringBuilder(); xmlBuilder.append("<doc>"); - for (int i = 0; i < (mLength * mEntityFraction); i++) { + for (int i = 0; i < (length * entityFraction); i++) { xmlBuilder.append("&"); } - while (xmlBuilder.length() < mLength) { + while (xmlBuilder.length() < length) { xmlBuilder.append("+"); } xmlBuilder.append("</doc>"); @@ -89,7 +81,9 @@ public final class XMLEntitiesPerfTest { } @Test - public void timeXmlParser() throws Exception { + @Parameters(method = "getData") + public void timeXmlParser(int length, float entityFraction) throws Exception { + setUp(length, entityFraction); BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { XmlPullParser parser = mXmlPullParserFactory.newPullParser(); @@ -101,7 +95,9 @@ public final class XMLEntitiesPerfTest { } @Test - public void timeDocumentBuilder() throws Exception { + @Parameters(method = "getData") + public void timeDocumentBuilder(int length, float entityFraction) throws Exception { + setUp(length, entityFraction); BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { DocumentBuilder documentBuilder = mDocumentBuilderFactory.newDocumentBuilder(); diff --git a/core/api/current.txt b/core/api/current.txt index eef2324c7a6c..218d7bd14ceb 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -172,6 +172,7 @@ package android { field public static final String REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE = "android.permission.REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE"; field public static final String REQUEST_PASSWORD_COMPLEXITY = "android.permission.REQUEST_PASSWORD_COMPLEXITY"; field @Deprecated public static final String RESTART_PACKAGES = "android.permission.RESTART_PACKAGES"; + field public static final String RUN_LONG_JOBS = "android.permission.RUN_LONG_JOBS"; field public static final String SCHEDULE_EXACT_ALARM = "android.permission.SCHEDULE_EXACT_ALARM"; field public static final String SEND_RESPOND_VIA_MESSAGE = "android.permission.SEND_RESPOND_VIA_MESSAGE"; field public static final String SEND_SMS = "android.permission.SEND_SMS"; @@ -44006,9 +44007,10 @@ package android.telephony { field public static final long NETWORK_TYPE_BITMASK_HSPA = 512L; // 0x200L field public static final long NETWORK_TYPE_BITMASK_HSPAP = 16384L; // 0x4000L field public static final long NETWORK_TYPE_BITMASK_HSUPA = 256L; // 0x100L + field public static final long NETWORK_TYPE_BITMASK_IDEN = 1024L; // 0x400L field public static final long NETWORK_TYPE_BITMASK_IWLAN = 131072L; // 0x20000L field public static final long NETWORK_TYPE_BITMASK_LTE = 4096L; // 0x1000L - field public static final long NETWORK_TYPE_BITMASK_LTE_CA = 262144L; // 0x40000L + field @Deprecated public static final long NETWORK_TYPE_BITMASK_LTE_CA = 262144L; // 0x40000L field public static final long NETWORK_TYPE_BITMASK_NR = 524288L; // 0x80000L field public static final long NETWORK_TYPE_BITMASK_TD_SCDMA = 65536L; // 0x10000L field public static final long NETWORK_TYPE_BITMASK_UMTS = 4L; // 0x4L diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index d1275f66383e..1b972e0cb81a 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -1353,9 +1353,16 @@ public class AppOpsManager { public static final int OP_RECEIVE_EXPLICIT_USER_INTERACTION_AUDIO = AppProtoEnums.APP_OP_RECEIVE_EXPLICIT_USER_INTERACTION_AUDIO; + /** + * App can schedule long running jobs. + * + * @hide + */ + public static final int OP_RUN_LONG_JOBS = AppProtoEnums.APP_OP_RUN_LONG_JOBS; + /** @hide */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public static final int _NUM_OP = 122; + public static final int _NUM_OP = 123; /** Access to coarse location information. */ public static final String OPSTR_COARSE_LOCATION = "android:coarse_location"; @@ -1839,6 +1846,13 @@ public class AppOpsManager { public static final String OPSTR_RECEIVE_EXPLICIT_USER_INTERACTION_AUDIO = "android:receive_explicit_user_interaction_audio"; + /** + * App can schedule long running jobs. + * + * @hide + */ + public static final String OPSTR_RUN_LONG_JOBS = "android:run_long_jobs"; + /** {@link #sAppOpsToNote} not initialized yet for this op */ private static final byte SHOULD_COLLECT_NOTE_OP_NOT_INITIALIZED = 0; /** Should not collect noting of this app-op in {@link #sAppOpsToNote} */ @@ -1933,6 +1947,7 @@ public class AppOpsManager { OP_SCHEDULE_EXACT_ALARM, OP_MANAGE_MEDIA, OP_TURN_SCREEN_ON, + OP_RUN_LONG_JOBS, }; static final AppOpInfo[] sAppOpInfos = new AppOpInfo[]{ @@ -2312,7 +2327,9 @@ public class AppOpsManager { new AppOpInfo.Builder(OP_RECEIVE_EXPLICIT_USER_INTERACTION_AUDIO, OPSTR_RECEIVE_EXPLICIT_USER_INTERACTION_AUDIO, "RECEIVE_EXPLICIT_USER_INTERACTION_AUDIO").setDefaultMode( - AppOpsManager.MODE_ALLOWED).build() + AppOpsManager.MODE_ALLOWED).build(), + new AppOpInfo.Builder(OP_RUN_LONG_JOBS, OPSTR_RUN_LONG_JOBS, "RUN_LONG_JOBS") + .setPermission(Manifest.permission.RUN_LONG_JOBS).build() }; /** diff --git a/core/java/android/app/backup/BackupRestoreEventLogger.java b/core/java/android/app/backup/BackupRestoreEventLogger.java index b789b38c966e..760c6f0fc333 100644 --- a/core/java/android/app/backup/BackupRestoreEventLogger.java +++ b/core/java/android/app/backup/BackupRestoreEventLogger.java @@ -19,10 +19,15 @@ package android.app.backup; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; +import android.util.Slog; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; -import java.util.Collections; +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; @@ -38,6 +43,8 @@ import java.util.Map; * @hide */ public class BackupRestoreEventLogger { + private static final String TAG = "BackupRestoreEventLogger"; + /** * Max number of unique data types for which an instance of this logger can store info. Attempts * to use more distinct data type values will be rejected. @@ -72,6 +79,8 @@ public class BackupRestoreEventLogger { public @interface BackupRestoreError {} private final int mOperationType; + private final Map<String, DataTypeResult> mResults = new HashMap<>(); + private final MessageDigest mHashDigest; /** * @param operationType type of the operation for which logging will be performed. See @@ -81,6 +90,14 @@ public class BackupRestoreEventLogger { */ public BackupRestoreEventLogger(@OperationType int operationType) { mOperationType = operationType; + + MessageDigest hashDigest = null; + try { + hashDigest = MessageDigest.getInstance("SHA-256"); + } catch (NoSuchAlgorithmException e) { + Slog.w("Couldn't create MessageDigest for hash computation", e); + } + mHashDigest = hashDigest; } /** @@ -98,7 +115,7 @@ public class BackupRestoreEventLogger { * @return boolean, indicating whether the log has been accepted. */ public boolean logItemsBackedUp(@NonNull @BackupRestoreDataType String dataType, int count) { - return true; + return logSuccess(OperationType.BACKUP, dataType, count); } /** @@ -118,7 +135,7 @@ public class BackupRestoreEventLogger { */ public boolean logItemsBackupFailed(@NonNull @BackupRestoreDataType String dataType, int count, @Nullable @BackupRestoreError String error) { - return true; + return logFailure(OperationType.BACKUP, dataType, count, error); } /** @@ -139,7 +156,7 @@ public class BackupRestoreEventLogger { */ public boolean logBackupMetaData(@NonNull @BackupRestoreDataType String dataType, @NonNull String metaData) { - return true; + return logMetaData(OperationType.BACKUP, dataType, metaData); } /** @@ -159,7 +176,7 @@ public class BackupRestoreEventLogger { * @return boolean, indicating whether the log has been accepted. */ public boolean logItemsRestored(@NonNull @BackupRestoreDataType String dataType, int count) { - return true; + return logSuccess(OperationType.RESTORE, dataType, count); } /** @@ -181,7 +198,7 @@ public class BackupRestoreEventLogger { */ public boolean logItemsRestoreFailed(@NonNull @BackupRestoreDataType String dataType, int count, @Nullable @BackupRestoreError String error) { - return true; + return logFailure(OperationType.RESTORE, dataType, count, error); } /** @@ -204,7 +221,7 @@ public class BackupRestoreEventLogger { */ public boolean logRestoreMetadata(@NonNull @BackupRestoreDataType String dataType, @NonNull String metadata) { - return true; + return logMetaData(OperationType.RESTORE, dataType, metadata); } /** @@ -214,7 +231,7 @@ public class BackupRestoreEventLogger { * @hide */ public List<DataTypeResult> getLoggingResults() { - return Collections.emptyList(); + return new ArrayList<>(mResults.values()); } /** @@ -227,22 +244,97 @@ public class BackupRestoreEventLogger { return mOperationType; } + private boolean logSuccess(@OperationType int operationType, + @BackupRestoreDataType String dataType, int count) { + DataTypeResult dataTypeResult = getDataTypeResult(operationType, dataType); + if (dataTypeResult == null) { + return false; + } + + dataTypeResult.mSuccessCount += count; + mResults.put(dataType, dataTypeResult); + + return true; + } + + private boolean logFailure(@OperationType int operationType, + @NonNull @BackupRestoreDataType String dataType, int count, + @Nullable @BackupRestoreError String error) { + DataTypeResult dataTypeResult = getDataTypeResult(operationType, dataType); + if (dataTypeResult == null) { + return false; + } + + dataTypeResult.mFailCount += count; + if (error != null) { + dataTypeResult.mErrors.merge(error, count, Integer::sum); + } + + return true; + } + + private boolean logMetaData(@OperationType int operationType, + @NonNull @BackupRestoreDataType String dataType, @NonNull String metaData) { + if (mHashDigest == null) { + return false; + } + DataTypeResult dataTypeResult = getDataTypeResult(operationType, dataType); + if (dataTypeResult == null) { + return false; + } + + dataTypeResult.mMetadataHash = getMetaDataHash(metaData); + + return true; + } + + /** + * Get the result container for the given data type. + * + * @return {@code DataTypeResult} object corresponding to the given {@code dataType} or + * {@code null} if the logger can't accept logs for the given data type. + */ + @Nullable + private DataTypeResult getDataTypeResult(@OperationType int operationType, + @BackupRestoreDataType String dataType) { + if (operationType != mOperationType) { + // Operation type for which we're trying to record logs doesn't match the operation + // type for which this logger instance was created. + Slog.d(TAG, "Operation type mismatch: logger created for " + mOperationType + + ", trying to log for " + operationType); + return null; + } + + if (!mResults.containsKey(dataType)) { + if (mResults.keySet().size() == DATA_TYPES_ALLOWED) { + // This is a new data type and we're already at capacity. + Slog.d(TAG, "Logger is full, ignoring new data type"); + return null; + } + + mResults.put(dataType, new DataTypeResult(dataType)); + } + + return mResults.get(dataType); + } + + private byte[] getMetaDataHash(String metaData) { + return mHashDigest.digest(metaData.getBytes(StandardCharsets.UTF_8)); + } + /** * Encapsulate logging results for a single data type. */ public static class DataTypeResult { @BackupRestoreDataType private final String mDataType; - private final int mSuccessCount; - private final Map<String, Integer> mErrors; - private final byte[] mMetadataHash; + private int mSuccessCount; + private int mFailCount; + private final Map<String, Integer> mErrors = new HashMap<>(); + private byte[] mMetadataHash; - public DataTypeResult(String dataType, int successCount, - Map<String, Integer> errors, byte[] metadataHash) { + public DataTypeResult(String dataType) { mDataType = dataType; - mSuccessCount = successCount; - mErrors = errors; - mMetadataHash = metadataHash; } @NonNull @@ -260,6 +352,13 @@ public class BackupRestoreEventLogger { } /** + * @return number of items of the given data type that have failed to back up or restore. + */ + public int getFailCount() { + return mFailCount; + } + + /** * @return mapping of {@link BackupRestoreError} to the count of items that are affected by * the error. */ diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index cbc1789b56fc..1df0fa8084a5 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -5202,6 +5202,15 @@ public abstract class Context { public static final String DROPBOX_SERVICE = "dropbox"; /** + * System service name for BackgroundInstallControlService. This service supervises the MBAs + * on device and provides the related metadata of the MBAs. + * + * @hide + */ + @SuppressLint("ServiceName") + public static final String BACKGROUND_INSTALL_CONTROL_SERVICE = "background_install_control"; + + /** * System service name for BinaryTransparencyService. This is used to retrieve measurements * pertaining to various pre-installed and system binaries on device for the purposes of * providing transparency to the user. diff --git a/core/jni/include_vm/android_runtime/vm.h b/core/java/android/content/pm/IBackgroundInstallControlService.aidl index a6e7c162d6ed..c8e7caebc821 100644 --- a/core/jni/include_vm/android_runtime/vm.h +++ b/core/java/android/content/pm/IBackgroundInstallControlService.aidl @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021 The Android Open Source Project + * Copyright (C) 2022 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,11 +14,13 @@ * limitations under the License. */ -#pragma once +package android.content.pm; -#include <jni.h> +import android.content.pm.ParceledListSlice; -// Get the Java VM. If the symbol doesn't exist at runtime, it means libandroid_runtime -// is not loaded in the current process. If the symbol exists but it returns nullptr, it -// means JavaVM is not yet started. -extern "C" JavaVM* AndroidRuntimeGetJavaVM(); +/** + * {@hide} + */ +interface IBackgroundInstallControlService { + ParceledListSlice getBackgroundInstalledPackages(long flags, int userId); +} diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java index 5403f089b308..3c73eb697a69 100644 --- a/core/java/android/hardware/fingerprint/FingerprintManager.java +++ b/core/java/android/hardware/fingerprint/FingerprintManager.java @@ -918,6 +918,22 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing } } + /** + * @hide + */ + @RequiresPermission(USE_BIOMETRIC_INTERNAL) + public void setUdfpsOverlay(@NonNull IUdfpsOverlay controller) { + if (mService == null) { + Slog.w(TAG, "setUdfpsOverlay: no fingerprint service"); + return; + } + + try { + mService.setUdfpsOverlay(controller); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } /** * Forwards BiometricStateListener to FingerprintService diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl index 051e3a4caa4e..365a6b3e06e5 100644 --- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl +++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl @@ -26,6 +26,7 @@ import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback import android.hardware.fingerprint.IFingerprintServiceReceiver; import android.hardware.fingerprint.IUdfpsOverlayController; import android.hardware.fingerprint.ISidefpsController; +import android.hardware.fingerprint.IUdfpsOverlay; import android.hardware.fingerprint.Fingerprint; import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; import java.util.List; @@ -201,6 +202,10 @@ interface IFingerprintService { @EnforcePermission("USE_BIOMETRIC_INTERNAL") void setSidefpsController(in ISidefpsController controller); + // Sets the controller for managing the UDFPS overlay. + @EnforcePermission("USE_BIOMETRIC_INTERNAL") + void setUdfpsOverlay(in IUdfpsOverlay controller); + // Registers BiometricStateListener. @EnforcePermission("USE_BIOMETRIC_INTERNAL") void registerBiometricStateListener(IBiometricStateListener listener); diff --git a/core/java/android/hardware/fingerprint/IUdfpsOverlay.aidl b/core/java/android/hardware/fingerprint/IUdfpsOverlay.aidl new file mode 100644 index 000000000000..c99fcccc68ea --- /dev/null +++ b/core/java/android/hardware/fingerprint/IUdfpsOverlay.aidl @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2022 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.fingerprint; + +/** + * Interface for interacting with the under-display fingerprint sensor (UDFPS) overlay. + * @hide + */ +oneway interface IUdfpsOverlay { + // Shows the overlay. + void show(long requestId, int sensorId, int reason); + + // Hides the overlay. + void hide(int sensorId); +} diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java index 26435586f2d7..3c4abab346a4 100644 --- a/core/java/android/os/Binder.java +++ b/core/java/android/os/Binder.java @@ -1219,25 +1219,40 @@ public class Binder implements IBinder { @UnsupportedAppUsage private boolean execTransact(int code, long dataObj, long replyObj, int flags) { + + Parcel data = Parcel.obtain(dataObj); + Parcel reply = Parcel.obtain(replyObj); + // At that point, the parcel request headers haven't been parsed so we do not know what // {@link WorkSource} the caller has set. Use calling UID as the default. - final int callingUid = Binder.getCallingUid(); - final long origWorkSource = ThreadLocalWorkSource.setUid(callingUid); + // + // TODO: this is wrong - we should attribute along the entire call route + // also this attribution logic should move to native code - it only works + // for Java now + // + // This attribution support is not generic and therefore not support in RPC mode + final int callingUid = data.isForRpc() ? -1 : Binder.getCallingUid(); + final long origWorkSource = callingUid == -1 + ? -1 : ThreadLocalWorkSource.setUid(callingUid); + try { - return execTransactInternal(code, dataObj, replyObj, flags, callingUid); + return execTransactInternal(code, data, reply, flags, callingUid); } finally { - ThreadLocalWorkSource.restore(origWorkSource); + reply.recycle(); + data.recycle(); + + if (callingUid != -1) { + ThreadLocalWorkSource.restore(origWorkSource); + } } } - private boolean execTransactInternal(int code, long dataObj, long replyObj, int flags, + private boolean execTransactInternal(int code, Parcel data, Parcel reply, int flags, int callingUid) { // Make sure the observer won't change while processing a transaction. final BinderInternal.Observer observer = sObserver; final CallSession callSession = observer != null ? observer.callStarted(this, code, UNSET_WORKSOURCE) : null; - Parcel data = Parcel.obtain(dataObj); - Parcel reply = Parcel.obtain(replyObj); // Theoretically, we should call transact, which will call onTransact, // but all that does is rewind it, and we just got these from an IPC, // so we'll just call it directly. @@ -1268,8 +1283,10 @@ public class Binder implements IBinder { final boolean tracingEnabled = tagEnabled && transactionTraceName != null; try { + // TODO - this logic should not be in Java - it should be in native + // code in libbinder so that it works for all binder users. final BinderCallHeavyHitterWatcher heavyHitterWatcher = sHeavyHitterWatcher; - if (heavyHitterWatcher != null) { + if (heavyHitterWatcher != null && callingUid != -1) { // Notify the heavy hitter watcher, if it's enabled. heavyHitterWatcher.onTransaction(callingUid, getClass(), code); } @@ -1277,7 +1294,10 @@ public class Binder implements IBinder { Trace.traceBegin(Trace.TRACE_TAG_AIDL, transactionTraceName); } - if ((flags & FLAG_COLLECT_NOTED_APP_OPS) != 0) { + // TODO - this logic should not be in Java - it should be in native + // code in libbinder so that it works for all binder users. Further, + // this should not re-use flags. + if ((flags & FLAG_COLLECT_NOTED_APP_OPS) != 0 && callingUid != -1) { AppOpsManager.startNotedAppOpsCollection(callingUid); try { res = onTransact(code, data, reply, flags); @@ -1320,8 +1340,6 @@ public class Binder implements IBinder { } checkParcel(this, code, reply, "Unreasonably large binder reply buffer"); - reply.recycle(); - data.recycle(); } // Just in case -- we are done with the IPC, so there should be no more strict diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java index d451765f022f..2afa87980c11 100644 --- a/core/java/android/os/Parcel.java +++ b/core/java/android/os/Parcel.java @@ -367,6 +367,8 @@ public final class Parcel { @FastNative private static native void nativeMarkForBinder(long nativePtr, IBinder binder); @CriticalNative + private static native boolean nativeIsForRpc(long nativePtr); + @CriticalNative private static native int nativeDataSize(long nativePtr); @CriticalNative private static native int nativeDataAvail(long nativePtr); @@ -644,6 +646,15 @@ public final class Parcel { nativeMarkForBinder(mNativePtr, binder); } + /** + * Whether this Parcel is written for an RPC transaction. + * + * @hide + */ + public final boolean isForRpc() { + return nativeIsForRpc(mNativePtr); + } + /** @hide */ @ParcelFlags @TestApi diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 4502eec9fe4f..897b7c3afe54 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -3374,9 +3374,26 @@ public final class Settings { } } - // Fetch all flags for the namespace at once for caching purposes - Bundle b = cp.call(cr.getAttributionSource(), - mProviderHolder.mUri.getAuthority(), mCallListCommand, null, args); + Bundle b; + // b/252663068: if we're in system server and the caller did not call + // clearCallingIdentity, the read would fail due to mismatched AttributionSources. + // TODO(b/256013480): remove this bypass after fixing the callers in system server. + if (namespace.equals(DeviceConfig.NAMESPACE_DEVICE_POLICY_MANAGER) + && Settings.isInSystemServer() + && Binder.getCallingUid() != Process.myUid()) { + final long token = Binder.clearCallingIdentity(); + try { + // Fetch all flags for the namespace at once for caching purposes + b = cp.call(cr.getAttributionSource(), + mProviderHolder.mUri.getAuthority(), mCallListCommand, null, args); + } finally { + Binder.restoreCallingIdentity(token); + } + } else { + // Fetch all flags for the namespace at once for caching purposes + b = cp.call(cr.getAttributionSource(), + mProviderHolder.mUri.getAuthority(), mCallListCommand, null, args); + } if (b == null) { // Invalid response, return an empty map return keyValues; diff --git a/core/java/android/text/method/BaseKeyListener.java b/core/java/android/text/method/BaseKeyListener.java index d4bcd12abd96..01989d54b871 100644 --- a/core/java/android/text/method/BaseKeyListener.java +++ b/core/java/android/text/method/BaseKeyListener.java @@ -229,6 +229,8 @@ public abstract class BaseKeyListener extends MetaKeyKeyListener break; } else if (Emoji.isEmojiModifierBase(codePoint)) { deleteCharCount += Character.charCount(codePoint); + state = STATE_BEFORE_EMOJI; + break; } state = STATE_FINISHED; break; diff --git a/core/jni/Android.bp b/core/jni/Android.bp index d59a51ab9174..c50abb3ff42a 100644 --- a/core/jni/Android.bp +++ b/core/jni/Android.bp @@ -329,7 +329,6 @@ cc_library_shared { header_libs: [ "bionic_libc_platform_headers", "dnsproxyd_protocol_headers", - "libandroid_runtime_vm_headers", ], }, host: { @@ -418,24 +417,3 @@ cc_library_shared { never: true, }, } - -cc_library_headers { - name: "libandroid_runtime_vm_headers", - host_supported: true, - vendor_available: true, - // TODO(b/153609531): remove when libbinder is not native_bridge_supported - native_bridge_supported: true, - // Allow only modules from the following list to create threads that can be - // attached to the JVM. This list should be a subset of the dependencies of - // libandroid_runtime. - visibility: [ - "//frameworks/native/libs/binder", - ], - export_include_dirs: ["include_vm"], - header_libs: [ - "jni_headers", - ], - export_header_lib_headers: [ - "jni_headers", - ], -} diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp index 422bdc98e9b5..9da28a3e56d2 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -22,7 +22,6 @@ #include <android-base/properties.h> #include <android/graphics/jni_runtime.h> #include <android_runtime/AndroidRuntime.h> -#include <android_runtime/vm.h> #include <assert.h> #include <binder/IBinder.h> #include <binder/IPCThreadState.h> diff --git a/core/jni/android_os_Parcel.cpp b/core/jni/android_os_Parcel.cpp index 1f64df49cb56..4d8dac1daaf0 100644 --- a/core/jni/android_os_Parcel.cpp +++ b/core/jni/android_os_Parcel.cpp @@ -116,6 +116,11 @@ static void android_os_Parcel_markForBinder(JNIEnv* env, jclass clazz, jlong nat } } +static jboolean android_os_Parcel_isForRpc(jlong nativePtr) { + Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr); + return parcel ? parcel->isForRpc() : false; +} + static jint android_os_Parcel_dataSize(jlong nativePtr) { Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr); @@ -808,6 +813,8 @@ static const JNINativeMethod gParcelMethods[] = { // @FastNative {"nativeMarkForBinder", "(JLandroid/os/IBinder;)V", (void*)android_os_Parcel_markForBinder}, // @CriticalNative + {"nativeIsForRpc", "(J)Z", (void*)android_os_Parcel_isForRpc}, + // @CriticalNative {"nativeDataSize", "(J)I", (void*)android_os_Parcel_dataSize}, // @CriticalNative {"nativeDataAvail", "(J)I", (void*)android_os_Parcel_dataAvail}, diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 554b15374943..62c584847c0f 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -6622,6 +6622,15 @@ <permission android:name="android.permission.MANAGE_DEVICE_LOCK_STATE" android:protectionLevel="internal|role" /> + <!-- Allows applications to use the long running jobs APIs. + <p>This is a special access permission that can be revoked by the system or the user. + <p>Apps need to target API {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} or above + to be able to request this permission. + <p>Protection level: appop + --> + <permission android:name="android.permission.RUN_LONG_JOBS" + android:protectionLevel="normal|appop"/> + <!-- Attribution for Geofencing service. --> <attribution android:tag="GeofencingService" android:label="@string/geofencing_service"/> <!-- Attribution for Country Detector. --> diff --git a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/ConversionUtilsTest.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/ConversionUtilsTest.java new file mode 100644 index 000000000000..31195548c968 --- /dev/null +++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/ConversionUtilsTest.java @@ -0,0 +1,221 @@ +/* + * Copyright (C) 2022 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.broadcastradio.aidl; + +import android.hardware.broadcastradio.AmFmBandRange; +import android.hardware.broadcastradio.AmFmRegionConfig; +import android.hardware.broadcastradio.DabTableEntry; +import android.hardware.broadcastradio.IdentifierType; +import android.hardware.broadcastradio.Properties; +import android.hardware.broadcastradio.VendorKeyValue; +import android.hardware.radio.Announcement; +import android.hardware.radio.ProgramSelector; +import android.hardware.radio.RadioManager; + +import com.google.common.truth.Expect; + +import org.junit.Rule; +import org.junit.Test; + +import java.util.Map; + +public final class ConversionUtilsTest { + + private static final int FM_LOWER_LIMIT = 87500; + private static final int FM_UPPER_LIMIT = 108000; + private static final int FM_SPACING = 200; + private static final int AM_LOWER_LIMIT = 540; + private static final int AM_UPPER_LIMIT = 1700; + private static final int AM_SPACING = 10; + private static final String DAB_ENTRY_LABEL_1 = "5A"; + private static final int DAB_ENTRY_FREQUENCY_1 = 174928; + private static final String DAB_ENTRY_LABEL_2 = "12D"; + private static final int DAB_ENTRY_FREQUENCY_2 = 229072; + private static final String VENDOR_INFO_KEY_1 = "vendorKey1"; + private static final String VENDOR_INFO_VALUE_1 = "vendorValue1"; + private static final String VENDOR_INFO_KEY_2 = "vendorKey2"; + private static final String VENDOR_INFO_VALUE_2 = "vendorValue2"; + private static final String TEST_SERVICE_NAME = "serviceMock"; + private static final int TEST_ID = 1; + private static final String TEST_MAKER = "makerMock"; + private static final String TEST_PRODUCT = "productMock"; + private static final String TEST_VERSION = "versionMock"; + private static final String TEST_SERIAL = "serialMock"; + + private static final int TEST_ENABLED_TYPE = Announcement.TYPE_EMERGENCY; + private static final int TEST_ANNOUNCEMENT_FREQUENCY = FM_LOWER_LIMIT + FM_SPACING; + + private static final RadioManager.ModuleProperties MODULE_PROPERTIES = + convertToModuleProperties(); + private static final Announcement ANNOUNCEMENT = + ConversionUtils.announcementFromHalAnnouncement( + AidlTestUtils.makeAnnouncement(TEST_ENABLED_TYPE, TEST_ANNOUNCEMENT_FREQUENCY)); + + @Rule + public final Expect expect = Expect.create(); + + @Test + public void propertiesFromHalProperties_idsMatch() { + expect.withMessage("Properties id") + .that(MODULE_PROPERTIES.getId()).isEqualTo(TEST_ID); + } + + @Test + public void propertiesFromHalProperties_serviceNamesMatch() { + expect.withMessage("Service name") + .that(MODULE_PROPERTIES.getServiceName()).isEqualTo(TEST_SERVICE_NAME); + } + + @Test + public void propertiesFromHalProperties_implementorsMatch() { + expect.withMessage("Implementor") + .that(MODULE_PROPERTIES.getImplementor()).isEqualTo(TEST_MAKER); + } + + + @Test + public void propertiesFromHalProperties_productsMatch() { + expect.withMessage("Product") + .that(MODULE_PROPERTIES.getProduct()).isEqualTo(TEST_PRODUCT); + } + + @Test + public void propertiesFromHalProperties_versionsMatch() { + expect.withMessage("Version") + .that(MODULE_PROPERTIES.getVersion()).isEqualTo(TEST_VERSION); + } + + @Test + public void propertiesFromHalProperties_serialsMatch() { + expect.withMessage("Serial") + .that(MODULE_PROPERTIES.getSerial()).isEqualTo(TEST_SERIAL); + } + + @Test + public void propertiesFromHalProperties_dabTableInfoMatch() { + Map<String, Integer> dabTableExpected = Map.of(DAB_ENTRY_LABEL_1, DAB_ENTRY_FREQUENCY_1, + DAB_ENTRY_LABEL_2, DAB_ENTRY_FREQUENCY_2); + + expect.withMessage("Supported program types") + .that(MODULE_PROPERTIES.getDabFrequencyTable()) + .containsExactlyEntriesIn(dabTableExpected); + } + + @Test + public void propertiesFromHalProperties_vendorInfoMatch() { + Map<String, String> vendorInfoExpected = Map.of(VENDOR_INFO_KEY_1, VENDOR_INFO_VALUE_1, + VENDOR_INFO_KEY_2, VENDOR_INFO_VALUE_2); + + expect.withMessage("Vendor info").that(MODULE_PROPERTIES.getVendorInfo()) + .containsExactlyEntriesIn(vendorInfoExpected); + } + + @Test + public void propertiesFromHalProperties_bandsMatch() { + RadioManager.BandDescriptor[] bands = MODULE_PROPERTIES.getBands(); + + expect.withMessage("Band descriptors").that(bands).hasLength(2); + + expect.withMessage("FM band frequency lower limit") + .that(bands[0].getLowerLimit()).isEqualTo(FM_LOWER_LIMIT); + expect.withMessage("FM band frequency upper limit") + .that(bands[0].getUpperLimit()).isEqualTo(FM_UPPER_LIMIT); + expect.withMessage("FM band frequency spacing") + .that(bands[0].getSpacing()).isEqualTo(FM_SPACING); + + expect.withMessage("AM band frequency lower limit") + .that(bands[1].getLowerLimit()).isEqualTo(AM_LOWER_LIMIT); + expect.withMessage("AM band frequency upper limit") + .that(bands[1].getUpperLimit()).isEqualTo(AM_UPPER_LIMIT); + expect.withMessage("AM band frequency spacing") + .that(bands[1].getSpacing()).isEqualTo(AM_SPACING); + } + + @Test + public void announcementFromHalAnnouncement_typesMatch() { + expect.withMessage("Announcement type") + .that(ANNOUNCEMENT.getType()).isEqualTo(TEST_ENABLED_TYPE); + } + + @Test + public void announcementFromHalAnnouncement_selectorsMatch() { + ProgramSelector.Identifier primaryIdExpected = new ProgramSelector.Identifier( + ProgramSelector.IDENTIFIER_TYPE_AMFM_FREQUENCY, TEST_ANNOUNCEMENT_FREQUENCY); + + ProgramSelector selector = ANNOUNCEMENT.getSelector(); + + expect.withMessage("Primary id of announcement selector") + .that(selector.getPrimaryId()).isEqualTo(primaryIdExpected); + expect.withMessage("Secondary ids of announcement selector") + .that(selector.getSecondaryIds()).isEmpty(); + } + + @Test + public void announcementFromHalAnnouncement_VendorInfoMatch() { + expect.withMessage("Announcement vendor info") + .that(ANNOUNCEMENT.getVendorInfo()).isEmpty(); + } + + private static RadioManager.ModuleProperties convertToModuleProperties() { + AmFmRegionConfig amFmConfig = createAmFmRegionConfig(); + DabTableEntry[] dabTableEntries = new DabTableEntry[]{ + createDabTableEntry(DAB_ENTRY_LABEL_1, DAB_ENTRY_FREQUENCY_1), + createDabTableEntry(DAB_ENTRY_LABEL_2, DAB_ENTRY_FREQUENCY_2)}; + Properties properties = createHalProperties(); + + return ConversionUtils.propertiesFromHalProperties(TEST_ID, TEST_SERVICE_NAME, properties, + amFmConfig, dabTableEntries); + } + + private static AmFmRegionConfig createAmFmRegionConfig() { + AmFmRegionConfig amFmRegionConfig = new AmFmRegionConfig(); + amFmRegionConfig.ranges = new AmFmBandRange[]{ + createAmFmBandRange(FM_LOWER_LIMIT, FM_UPPER_LIMIT, FM_SPACING), + createAmFmBandRange(AM_LOWER_LIMIT, AM_UPPER_LIMIT, AM_SPACING)}; + return amFmRegionConfig; + } + + private static AmFmBandRange createAmFmBandRange(int lowerBound, int upperBound, int spacing) { + AmFmBandRange bandRange = new AmFmBandRange(); + bandRange.lowerBound = lowerBound; + bandRange.upperBound = upperBound; + bandRange.spacing = spacing; + bandRange.seekSpacing = bandRange.spacing; + return bandRange; + } + + private static DabTableEntry createDabTableEntry(String label, int value) { + DabTableEntry dabTableEntry = new DabTableEntry(); + dabTableEntry.label = label; + dabTableEntry.frequencyKhz = value; + return dabTableEntry; + } + + private static Properties createHalProperties() { + Properties halProperties = new Properties(); + halProperties.supportedIdentifierTypes = new int[]{IdentifierType.AMFM_FREQUENCY_KHZ, + IdentifierType.RDS_PI, IdentifierType.DAB_SID_EXT}; + halProperties.maker = TEST_MAKER; + halProperties.product = TEST_PRODUCT; + halProperties.version = TEST_VERSION; + halProperties.serial = TEST_SERIAL; + halProperties.vendorInfo = new VendorKeyValue[]{ + AidlTestUtils.makeVendorKeyValue(VENDOR_INFO_KEY_1, VENDOR_INFO_VALUE_1), + AidlTestUtils.makeVendorKeyValue(VENDOR_INFO_KEY_2, VENDOR_INFO_VALUE_2)}; + return halProperties; + } +} diff --git a/core/tests/coretests/OWNERS b/core/tests/coretests/OWNERS index 0fb0c3021486..e8c9fe70272d 100644 --- a/core/tests/coretests/OWNERS +++ b/core/tests/coretests/OWNERS @@ -1 +1,4 @@ include platform/frameworks/base:/services/core/java/com/android/server/am/OWNERS + +per-file BinderTest.java = file:platform/frameworks/native:/libs/binder/OWNERS +per-file ParcelTest.java = file:platform/frameworks/native:/libs/binder/OWNERS diff --git a/core/tests/coretests/src/android/app/backup/BackupRestoreEventLoggerTest.java b/core/tests/coretests/src/android/app/backup/BackupRestoreEventLoggerTest.java new file mode 100644 index 000000000000..67b24ec17a27 --- /dev/null +++ b/core/tests/coretests/src/android/app/backup/BackupRestoreEventLoggerTest.java @@ -0,0 +1,277 @@ +/* + * Copyright (C) 2022 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.app.backup; + +import static android.app.backup.BackupRestoreEventLogger.OperationType.BACKUP; +import static android.app.backup.BackupRestoreEventLogger.OperationType.RESTORE; + +import static com.google.common.truth.Truth.assertThat; + +import static junit.framework.Assert.fail; + +import android.app.backup.BackupRestoreEventLogger.BackupRestoreDataType; +import android.app.backup.BackupRestoreEventLogger.DataTypeResult; +import android.platform.test.annotations.Presubmit; + +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; +import java.util.Arrays; +import java.util.List; +import java.util.Optional; + +@Presubmit +@RunWith(AndroidJUnit4.class) +public class BackupRestoreEventLoggerTest { + private static final int DATA_TYPES_ALLOWED = 15; + + private static final String DATA_TYPE_1 = "data_type_1"; + private static final String DATA_TYPE_2 = "data_type_2"; + private static final String ERROR_1 = "error_1"; + private static final String ERROR_2 = "error_2"; + private static final String METADATA_1 = "metadata_1"; + private static final String METADATA_2 = "metadata_2"; + + private BackupRestoreEventLogger mLogger; + private MessageDigest mHashDigest; + + @Before + public void setUp() throws Exception { + mHashDigest = MessageDigest.getInstance("SHA-256"); + } + + @Test + public void testBackupLogger_rejectsRestoreLogs() { + mLogger = new BackupRestoreEventLogger(BACKUP); + + assertThat(mLogger.logItemsRestored(DATA_TYPE_1, /* count */ 5)).isFalse(); + assertThat(mLogger.logItemsRestoreFailed(DATA_TYPE_1, /* count */ 5, ERROR_1)).isFalse(); + assertThat(mLogger.logRestoreMetadata(DATA_TYPE_1, /* metadata */ "metadata")).isFalse(); + } + + @Test + public void testRestoreLogger_rejectsBackupLogs() { + mLogger = new BackupRestoreEventLogger(RESTORE); + + assertThat(mLogger.logItemsBackedUp(DATA_TYPE_1, /* count */ 5)).isFalse(); + assertThat(mLogger.logItemsBackupFailed(DATA_TYPE_1, /* count */ 5, ERROR_1)).isFalse(); + assertThat(mLogger.logBackupMetaData(DATA_TYPE_1, /* metadata */ "metadata")).isFalse(); + } + + @Test + public void testBackupLogger_onlyAcceptsAllowedNumberOfDataTypes() { + mLogger = new BackupRestoreEventLogger(BACKUP); + + for (int i = 0; i < DATA_TYPES_ALLOWED; i++) { + String dataType = DATA_TYPE_1 + i; + assertThat(mLogger.logItemsBackedUp(dataType, /* count */ 5)).isTrue(); + assertThat(mLogger.logItemsBackupFailed(dataType, /* count */ 5, /* error */ null)) + .isTrue(); + assertThat(mLogger.logBackupMetaData(dataType, METADATA_1)).isTrue(); + } + + assertThat(mLogger.logItemsBackedUp(DATA_TYPE_2, /* count */ 5)).isFalse(); + assertThat(mLogger.logItemsBackupFailed(DATA_TYPE_2, /* count */ 5, /* error */ null)) + .isFalse(); + assertThat(mLogger.logRestoreMetadata(DATA_TYPE_2, METADATA_1)).isFalse(); + assertThat(getResultForDataTypeIfPresent(mLogger, DATA_TYPE_2)).isEqualTo(Optional.empty()); + } + + @Test + public void testRestoreLogger_onlyAcceptsAllowedNumberOfDataTypes() { + mLogger = new BackupRestoreEventLogger(RESTORE); + + for (int i = 0; i < DATA_TYPES_ALLOWED; i++) { + String dataType = DATA_TYPE_1 + i; + assertThat(mLogger.logItemsRestored(dataType, /* count */ 5)).isTrue(); + assertThat(mLogger.logItemsRestoreFailed(dataType, /* count */ 5, /* error */ null)) + .isTrue(); + assertThat(mLogger.logRestoreMetadata(dataType, METADATA_1)).isTrue(); + } + + assertThat(mLogger.logItemsRestored(DATA_TYPE_2, /* count */ 5)).isFalse(); + assertThat(mLogger.logItemsRestoreFailed(DATA_TYPE_2, /* count */ 5, /* error */ null)) + .isFalse(); + assertThat(mLogger.logRestoreMetadata(DATA_TYPE_2, METADATA_1)).isFalse(); + assertThat(getResultForDataTypeIfPresent(mLogger, DATA_TYPE_2)).isEqualTo(Optional.empty()); + } + + @Test + public void testLogBackupMetadata_repeatedCalls_recordsLatestMetadataHash() { + mLogger = new BackupRestoreEventLogger(BACKUP); + + mLogger.logBackupMetaData(DATA_TYPE_1, METADATA_1); + mLogger.logBackupMetaData(DATA_TYPE_1, METADATA_2); + + byte[] recordedHash = getResultForDataType(mLogger, DATA_TYPE_1).getMetadataHash(); + byte[] expectedHash = getMetaDataHash(METADATA_2); + assertThat(Arrays.equals(recordedHash, expectedHash)).isTrue(); + } + + @Test + public void testLogRestoreMetadata_repeatedCalls_recordsLatestMetadataHash() { + mLogger = new BackupRestoreEventLogger(RESTORE); + + mLogger.logRestoreMetadata(DATA_TYPE_1, METADATA_1); + mLogger.logRestoreMetadata(DATA_TYPE_1, METADATA_2); + + byte[] recordedHash = getResultForDataType(mLogger, DATA_TYPE_1).getMetadataHash(); + byte[] expectedHash = getMetaDataHash(METADATA_2); + assertThat(Arrays.equals(recordedHash, expectedHash)).isTrue(); + } + + @Test + public void testLogItemsBackedUp_repeatedCalls_recordsTotalItems() { + mLogger = new BackupRestoreEventLogger(BACKUP); + + int firstCount = 10; + int secondCount = 5; + mLogger.logItemsBackedUp(DATA_TYPE_1, firstCount); + mLogger.logItemsBackedUp(DATA_TYPE_1, secondCount); + + int dataTypeCount = getResultForDataType(mLogger, DATA_TYPE_1).getSuccessCount(); + assertThat(dataTypeCount).isEqualTo(firstCount + secondCount); + } + + @Test + public void testLogItemsRestored_repeatedCalls_recordsTotalItems() { + mLogger = new BackupRestoreEventLogger(RESTORE); + + int firstCount = 10; + int secondCount = 5; + mLogger.logItemsRestored(DATA_TYPE_1, firstCount); + mLogger.logItemsRestored(DATA_TYPE_1, secondCount); + + int dataTypeCount = getResultForDataType(mLogger, DATA_TYPE_1).getSuccessCount(); + assertThat(dataTypeCount).isEqualTo(firstCount + secondCount); + } + + @Test + public void testLogItemsBackedUp_multipleDataTypes_recordsEachDataType() { + mLogger = new BackupRestoreEventLogger(BACKUP); + + int firstCount = 10; + int secondCount = 5; + mLogger.logItemsBackedUp(DATA_TYPE_1, firstCount); + mLogger.logItemsBackedUp(DATA_TYPE_2, secondCount); + + int firstDataTypeCount = getResultForDataType(mLogger, DATA_TYPE_1).getSuccessCount(); + int secondDataTypeCount = getResultForDataType(mLogger, DATA_TYPE_2).getSuccessCount(); + assertThat(firstDataTypeCount).isEqualTo(firstCount); + assertThat(secondDataTypeCount).isEqualTo(secondCount); + } + + @Test + public void testLogItemsRestored_multipleDataTypes_recordsEachDataType() { + mLogger = new BackupRestoreEventLogger(RESTORE); + + int firstCount = 10; + int secondCount = 5; + mLogger.logItemsRestored(DATA_TYPE_1, firstCount); + mLogger.logItemsRestored(DATA_TYPE_2, secondCount); + + int firstDataTypeCount = getResultForDataType(mLogger, DATA_TYPE_1).getSuccessCount(); + int secondDataTypeCount = getResultForDataType(mLogger, DATA_TYPE_2).getSuccessCount(); + assertThat(firstDataTypeCount).isEqualTo(firstCount); + assertThat(secondDataTypeCount).isEqualTo(secondCount); + } + + @Test + public void testLogItemsBackupFailed_repeatedCalls_recordsTotalItems() { + mLogger = new BackupRestoreEventLogger(BACKUP); + + int firstCount = 10; + int secondCount = 5; + mLogger.logItemsBackupFailed(DATA_TYPE_1, firstCount, /* error */ null); + mLogger.logItemsBackupFailed(DATA_TYPE_1, secondCount, "error"); + + int dataTypeCount = getResultForDataType(mLogger, DATA_TYPE_1).getFailCount(); + assertThat(dataTypeCount).isEqualTo(firstCount + secondCount); + } + + @Test + public void testLogItemsRestoreFailed_repeatedCalls_recordsTotalItems() { + mLogger = new BackupRestoreEventLogger(RESTORE); + + int firstCount = 10; + int secondCount = 5; + mLogger.logItemsRestoreFailed(DATA_TYPE_1, firstCount, /* error */ null); + mLogger.logItemsRestoreFailed(DATA_TYPE_1, secondCount, "error"); + + int dataTypeCount = getResultForDataType(mLogger, DATA_TYPE_1).getFailCount(); + assertThat(dataTypeCount).isEqualTo(firstCount + secondCount); + } + + @Test + public void testLogItemsBackupFailed_multipleErrors_recordsEachError() { + mLogger = new BackupRestoreEventLogger(BACKUP); + + int firstCount = 10; + int secondCount = 5; + mLogger.logItemsBackupFailed(DATA_TYPE_1, firstCount, ERROR_1); + mLogger.logItemsBackupFailed(DATA_TYPE_1, secondCount, ERROR_2); + + int firstErrorTypeCount = getResultForDataType(mLogger, DATA_TYPE_1) + .getErrors().get(ERROR_1); + int secondErrorTypeCount = getResultForDataType(mLogger, DATA_TYPE_1) + .getErrors().get(ERROR_2); + assertThat(firstErrorTypeCount).isEqualTo(firstCount); + assertThat(secondErrorTypeCount).isEqualTo(secondCount); + } + + @Test + public void testLogItemsRestoreFailed_multipleErrors_recordsEachError() { + mLogger = new BackupRestoreEventLogger(RESTORE); + + int firstCount = 10; + int secondCount = 5; + mLogger.logItemsRestoreFailed(DATA_TYPE_1, firstCount, ERROR_1); + mLogger.logItemsRestoreFailed(DATA_TYPE_1, secondCount, ERROR_2); + + int firstErrorTypeCount = getResultForDataType(mLogger, DATA_TYPE_1) + .getErrors().get(ERROR_1); + int secondErrorTypeCount = getResultForDataType(mLogger, DATA_TYPE_1) + .getErrors().get(ERROR_2); + assertThat(firstErrorTypeCount).isEqualTo(firstCount); + assertThat(secondErrorTypeCount).isEqualTo(secondCount); + } + + private static DataTypeResult getResultForDataType(BackupRestoreEventLogger logger, + @BackupRestoreDataType String dataType) { + Optional<DataTypeResult> result = getResultForDataTypeIfPresent(logger, dataType); + if (result.isEmpty()) { + fail("Failed to find result for data type: " + dataType); + } + return result.get(); + } + + private static Optional<DataTypeResult> getResultForDataTypeIfPresent( + BackupRestoreEventLogger logger, @BackupRestoreDataType String dataType) { + List<DataTypeResult> resultList = logger.getLoggingResults(); + return resultList.stream().filter( + dataTypeResult -> dataTypeResult.getDataType().equals(dataType)).findAny(); + } + + private byte[] getMetaDataHash(String metaData) { + return mHashDigest.digest(metaData.getBytes(StandardCharsets.UTF_8)); + } +} diff --git a/core/tests/coretests/src/android/os/ParcelTest.java b/core/tests/coretests/src/android/os/ParcelTest.java index fdd278b9c621..e2fe87b4cfe3 100644 --- a/core/tests/coretests/src/android/os/ParcelTest.java +++ b/core/tests/coretests/src/android/os/ParcelTest.java @@ -37,6 +37,13 @@ public class ParcelTest { private static final String INTERFACE_TOKEN_2 = "Another IBinder interface token"; @Test + public void testIsForRpc() { + Parcel p = Parcel.obtain(); + assertEquals(false, p.isForRpc()); + p.recycle(); + } + + @Test public void testCallingWorkSourceUidAfterWrite() { Parcel p = Parcel.obtain(); // Method does not throw if replaceCallingWorkSourceUid is called before requests headers diff --git a/core/tests/coretests/src/android/text/method/BackspaceTest.java b/core/tests/coretests/src/android/text/method/BackspaceTest.java index ddae652cec05..19c2c6153558 100644 --- a/core/tests/coretests/src/android/text/method/BackspaceTest.java +++ b/core/tests/coretests/src/android/text/method/BackspaceTest.java @@ -193,11 +193,15 @@ public class BackspaceTest { backspace(state, 0); state.assertEquals("|"); - // Emoji modifier can be appended to the first emoji. + // Emoji modifier can be appended to each emoji. state.setByString("U+1F469 U+1F3FB U+200D U+1F4BC |"); backspace(state, 0); state.assertEquals("|"); + state.setByString("U+1F468 U+1F3FF U+200D U+2764 U+FE0F U+200D U+1F468 U+1F3FB |"); + backspace(state, 0); + state.assertEquals("|"); + // End with ZERO WIDTH JOINER state.setByString("U+1F441 U+200D |"); backspace(state, 0); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeStatus.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeStatus.java index 195ff502e7dc..2fafe67664f8 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeStatus.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeStatus.java @@ -48,7 +48,6 @@ public class DesktopModeStatus { try { int result = Settings.System.getIntForUser(context.getContentResolver(), Settings.System.DESKTOP_MODE, UserHandle.USER_CURRENT); - ProtoLog.d(WM_SHELL_DESKTOP_MODE, "isDesktopModeEnabled=%s", result); return result != 0; } catch (Exception e) { ProtoLog.e(WM_SHELL_DESKTOP_MODE, "Failed to read DESKTOP_MODE setting %s", e); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepository.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepository.kt index c91d54a62ae6..b7749fc4c3d4 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepository.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepository.kt @@ -69,22 +69,28 @@ class DesktopModeTaskRepository { /** * Mark a task with given [taskId] as active. + * + * @return `true` if the task was not active */ - fun addActiveTask(taskId: Int) { + fun addActiveTask(taskId: Int): Boolean { val added = activeTasks.add(taskId) if (added) { activeTasksListeners.onEach { it.onActiveTasksChanged() } } + return added } /** * Remove task with given [taskId] from active tasks. + * + * @return `true` if the task was active */ - fun removeActiveTask(taskId: Int) { + fun removeActiveTask(taskId: Int): Boolean { val removed = activeTasks.remove(taskId) if (removed) { activeTasksListeners.onEach { it.onActiveTasksChanged() } } + return removed } /** diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java index eaa7158abbe5..90b35a5a55e1 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java @@ -87,11 +87,13 @@ public class FreeformTaskListener implements ShellTaskOrganizer.TaskListener { } if (DesktopModeStatus.IS_SUPPORTED && taskInfo.isVisible) { - ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE, - "Adding active freeform task: #%d", taskInfo.taskId); - mDesktopModeTaskRepository.ifPresent(it -> it.addActiveTask(taskInfo.taskId)); - mDesktopModeTaskRepository.ifPresent( - it -> it.updateVisibleFreeformTasks(taskInfo.taskId, true)); + mDesktopModeTaskRepository.ifPresent(repository -> { + if (repository.addActiveTask(taskInfo.taskId)) { + ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE, + "Adding active freeform task: #%d", taskInfo.taskId); + } + repository.updateVisibleFreeformTasks(taskInfo.taskId, true); + }); } } @@ -102,11 +104,13 @@ public class FreeformTaskListener implements ShellTaskOrganizer.TaskListener { mTasks.remove(taskInfo.taskId); if (DesktopModeStatus.IS_SUPPORTED) { - ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE, - "Removing active freeform task: #%d", taskInfo.taskId); - mDesktopModeTaskRepository.ifPresent(it -> it.removeActiveTask(taskInfo.taskId)); - mDesktopModeTaskRepository.ifPresent( - it -> it.updateVisibleFreeformTasks(taskInfo.taskId, false)); + mDesktopModeTaskRepository.ifPresent(repository -> { + if (repository.removeActiveTask(taskInfo.taskId)) { + ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE, + "Removing active freeform task: #%d", taskInfo.taskId); + } + repository.updateVisibleFreeformTasks(taskInfo.taskId, false); + }); } if (!Transitions.ENABLE_SHELL_TRANSITIONS) { @@ -123,13 +127,15 @@ public class FreeformTaskListener implements ShellTaskOrganizer.TaskListener { mWindowDecorationViewModel.onTaskInfoChanged(state.mTaskInfo); if (DesktopModeStatus.IS_SUPPORTED) { - if (taskInfo.isVisible) { - ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE, - "Adding active freeform task: #%d", taskInfo.taskId); - mDesktopModeTaskRepository.ifPresent(it -> it.addActiveTask(taskInfo.taskId)); - } - mDesktopModeTaskRepository.ifPresent( - it -> it.updateVisibleFreeformTasks(taskInfo.taskId, taskInfo.isVisible)); + mDesktopModeTaskRepository.ifPresent(repository -> { + if (taskInfo.isVisible) { + if (repository.addActiveTask(taskInfo.taskId)) { + ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE, + "Adding active freeform task: #%d", taskInfo.taskId); + } + } + repository.updateVisibleFreeformTasks(taskInfo.taskId, taskInfo.isVisible); + }); } } diff --git a/packages/SettingsLib/Spa/spa/build.gradle b/packages/SettingsLib/Spa/spa/build.gradle index 2820ed7bc96e..3b159e95cc55 100644 --- a/packages/SettingsLib/Spa/spa/build.gradle +++ b/packages/SettingsLib/Spa/spa/build.gradle @@ -59,9 +59,9 @@ dependencies { api "androidx.compose.material:material-icons-extended:$jetpack_compose_version" api "androidx.compose.runtime:runtime-livedata:$jetpack_compose_version" api "androidx.compose.ui:ui-tooling-preview:$jetpack_compose_version" - api "androidx.lifecycle:lifecycle-livedata-ktx:2.6.0-alpha02" + api "androidx.lifecycle:lifecycle-livedata-ktx:2.6.0-alpha03" api "androidx.navigation:navigation-compose:2.5.0" - api "com.google.android.material:material:1.6.1" + api "com.google.android.material:material:1.7.0-alpha03" debugApi "androidx.compose.ui:ui-tooling:$jetpack_compose_version" implementation "com.airbnb.android:lottie-compose:5.2.0" } diff --git a/packages/SettingsLib/Spa/spa/res/values-night/themes.xml b/packages/SettingsLib/Spa/spa/res/values-night/themes.xml deleted file mode 100644 index 67dd2b0cc5e0..000000000000 --- a/packages/SettingsLib/Spa/spa/res/values-night/themes.xml +++ /dev/null @@ -1,20 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - Copyright (C) 2022 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> - - <style name="Theme.SpaLib.DayNight" /> -</resources> diff --git a/packages/SettingsLib/Spa/spa/res/values/themes.xml b/packages/SettingsLib/Spa/spa/res/values/themes.xml index e0e5fc211ec6..25846ec2d20b 100644 --- a/packages/SettingsLib/Spa/spa/res/values/themes.xml +++ b/packages/SettingsLib/Spa/spa/res/values/themes.xml @@ -16,12 +16,10 @@ --> <resources> - <style name="Theme.SpaLib" parent="Theme.Material3.DayNight.NoActionBar"> + <style name="Theme.SpaLib" parent="@android:style/Theme.DeviceDefault.Settings"> <item name="android:statusBarColor">@android:color/transparent</item> <item name="android:navigationBarColor">@android:color/transparent</item> - </style> - - <style name="Theme.SpaLib.DayNight"> - <item name="android:windowLightStatusBar">true</item> + <item name="android:windowActionBar">false</item> + <item name="android:windowNoTitle">true</item> </style> </resources> diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/BrowseActivity.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/BrowseActivity.kt index d3efaa7480f8..c3c90ab4fdb8 100644 --- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/BrowseActivity.kt +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/BrowseActivity.kt @@ -27,6 +27,7 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.platform.LocalLifecycleOwner +import androidx.core.view.WindowCompat import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleEventObserver import androidx.navigation.NavGraph.Companion.findStartDestination @@ -66,8 +67,9 @@ open class BrowseActivity : ComponentActivity() { private val spaEnvironment get() = SpaEnvironmentFactory.instance override fun onCreate(savedInstanceState: Bundle?) { - setTheme(R.style.Theme_SpaLib_DayNight) + setTheme(R.style.Theme_SpaLib) super.onCreate(savedInstanceState) + WindowCompat.setDecorFitsSystemWindows(window, false) spaEnvironment.logger.message(TAG, "onCreate", category = LogCategory.FRAMEWORK) setContent { @@ -83,35 +85,19 @@ open class BrowseActivity : ComponentActivity() { val navController = rememberNavController() val nullPage = SettingsPage.createNull() CompositionLocalProvider(navController.localNavController()) { - NavHost(navController, nullPage.sppName) { + NavHost( + navController = navController, + startDestination = nullPage.sppName, + ) { composable(nullPage.sppName) {} for (spp in sppRepository.getAllProviders()) { composable( route = spp.name + spp.parameter.navRoute(), arguments = spp.parameter, ) { navBackStackEntry -> - val lifecycleOwner = LocalLifecycleOwner.current - val sp = remember(navBackStackEntry.arguments) { + PageLogger(remember(navBackStackEntry.arguments) { spp.createSettingsPage(arguments = navBackStackEntry.arguments) - } - - DisposableEffect(lifecycleOwner) { - val observer = LifecycleEventObserver { _, event -> - if (event == Lifecycle.Event.ON_START) { - sp.enterPage() - } else if (event == Lifecycle.Event.ON_STOP) { - sp.leavePage() - } - } - - // Add the observer to the lifecycle - lifecycleOwner.lifecycle.addObserver(observer) - - // When the effect leaves the Composition, remove the observer - onDispose { - lifecycleOwner.lifecycle.removeObserver(observer) - } - } + }) spp.Page(navBackStackEntry.arguments) } @@ -122,6 +108,28 @@ open class BrowseActivity : ComponentActivity() { } @Composable + private fun PageLogger(settingsPage: SettingsPage) { + val lifecycleOwner = LocalLifecycleOwner.current + DisposableEffect(lifecycleOwner) { + val observer = LifecycleEventObserver { _, event -> + if (event == Lifecycle.Event.ON_START) { + settingsPage.enterPage() + } else if (event == Lifecycle.Event.ON_STOP) { + settingsPage.leavePage() + } + } + + // Add the observer to the lifecycle + lifecycleOwner.lifecycle.addObserver(observer) + + // When the effect leaves the Composition, remove the observer + onDispose { + lifecycleOwner.lifecycle.removeObserver(observer) + } + } + } + + @Composable private fun InitialDestinationNavigator() { val sppRepository by spaEnvironment.pageProviderRepository val destinationNavigated = rememberSaveable { mutableStateOf(false) } diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/PaddingValuesExt.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/PaddingValuesExt.kt new file mode 100644 index 000000000000..18335ff6eba5 --- /dev/null +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/PaddingValuesExt.kt @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2022 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.framework.compose + +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.LayoutDirection +import androidx.compose.ui.unit.dp + +internal fun PaddingValues.horizontalValues(): PaddingValues = HorizontalPaddingValues(this) + +internal fun PaddingValues.verticalValues(): PaddingValues = VerticalPaddingValues(this) + +private class HorizontalPaddingValues(private val paddingValues: PaddingValues) : PaddingValues { + override fun calculateLeftPadding(layoutDirection: LayoutDirection) = + paddingValues.calculateLeftPadding(layoutDirection) + + override fun calculateTopPadding(): Dp = 0.dp + + override fun calculateRightPadding(layoutDirection: LayoutDirection) = + paddingValues.calculateRightPadding(layoutDirection) + + override fun calculateBottomPadding() = 0.dp +} + +private class VerticalPaddingValues(private val paddingValues: PaddingValues) : PaddingValues { + override fun calculateLeftPadding(layoutDirection: LayoutDirection) = 0.dp + + override fun calculateTopPadding(): Dp = paddingValues.calculateTopPadding() + + override fun calculateRightPadding(layoutDirection: LayoutDirection) = 0.dp + + override fun calculateBottomPadding() = paddingValues.calculateBottomPadding() +} diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/debug/DebugActivity.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/debug/DebugActivity.kt index 9eaa88ae3168..26491d51e838 100644 --- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/debug/DebugActivity.kt +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/debug/DebugActivity.kt @@ -62,7 +62,7 @@ class DebugActivity : ComponentActivity() { private val spaEnvironment get() = SpaEnvironmentFactory.instance override fun onCreate(savedInstanceState: Bundle?) { - setTheme(R.style.Theme_SpaLib_DayNight) + setTheme(R.style.Theme_SpaLib) super.onCreate(savedInstanceState) spaEnvironment.logger.message(TAG, "onCreate", category = LogCategory.FRAMEWORK) diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/HomeScaffold.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/HomeScaffold.kt index eb20ac5c5f09..711c8a753532 100644 --- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/HomeScaffold.kt +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/HomeScaffold.kt @@ -20,6 +20,7 @@ import androidx.compose.foundation.background import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.systemBarsPadding import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material3.MaterialTheme @@ -34,6 +35,7 @@ fun HomeScaffold(title: String, content: @Composable () -> Unit) { Modifier .fillMaxSize() .background(color = MaterialTheme.colorScheme.background) + .systemBarsPadding() .verticalScroll(rememberScrollState()), ) { Text( diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/RegularScaffold.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/RegularScaffold.kt index 9a17b2a8cb78..d17a8dcd0161 100644 --- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/RegularScaffold.kt +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/RegularScaffold.kt @@ -19,7 +19,7 @@ package com.android.settingslib.spa.widget.scaffold import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.RowScope import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.height import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material3.Scaffold @@ -27,6 +27,8 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.tooling.preview.Preview import com.android.settingslib.spa.framework.theme.SettingsTheme +import com.android.settingslib.spa.widget.preference.Preference +import com.android.settingslib.spa.widget.preference.PreferenceModel /** * A [Scaffold] which content is scrollable and wrapped in a [Column]. @@ -42,8 +44,9 @@ fun RegularScaffold( ) { SettingsScaffold(title, actions) { paddingValues -> Column(Modifier.verticalScroll(rememberScrollState())) { - Spacer(Modifier.padding(paddingValues)) + Spacer(Modifier.height(paddingValues.calculateTopPadding())) content() + Spacer(Modifier.height(paddingValues.calculateBottomPadding())) } } } @@ -52,6 +55,13 @@ fun RegularScaffold( @Composable private fun RegularScaffoldPreview() { SettingsTheme { - RegularScaffold(title = "Display") {} + RegularScaffold(title = "Display") { + Preference(object : PreferenceModel { + override val title = "Item 1" + }) + Preference(object : PreferenceModel { + override val title = "Item 2" + }) + } } } diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SearchScaffold.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SearchScaffold.kt index 4f83ad6bd291..efc623af9cc0 100644 --- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SearchScaffold.kt +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SearchScaffold.kt @@ -14,13 +14,12 @@ * limitations under the License. */ -@file:OptIn(ExperimentalMaterial3Api::class) - package com.android.settingslib.spa.widget.scaffold import androidx.activity.compose.BackHandler import androidx.appcompat.R import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.RowScope import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth @@ -31,10 +30,13 @@ import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold +import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.material3.TextField import androidx.compose.material3.TextFieldDefaults import androidx.compose.material3.TopAppBar +import androidx.compose.material3.TopAppBarDefaults +import androidx.compose.material3.TopAppBarScrollBehavior import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.State @@ -48,45 +50,57 @@ import androidx.compose.ui.draw.alpha import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.focus.focusRequester import androidx.compose.ui.graphics.Color +import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.TextFieldValue import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.Dp import androidx.lifecycle.ViewModel import androidx.lifecycle.viewmodel.compose.viewModel import com.android.settingslib.spa.framework.compose.hideKeyboardAction +import com.android.settingslib.spa.framework.compose.horizontalValues import com.android.settingslib.spa.framework.theme.SettingsOpacity import com.android.settingslib.spa.framework.theme.SettingsTheme +import com.android.settingslib.spa.widget.preference.Preference +import com.android.settingslib.spa.widget.preference.PreferenceModel /** * A [Scaffold] which content is can be full screen, and with a search feature built-in. */ +@OptIn(ExperimentalMaterial3Api::class) @Composable fun SearchScaffold( title: String, actions: @Composable RowScope.() -> Unit = {}, - content: @Composable (searchQuery: State<String>) -> Unit, + content: @Composable (bottomPadding: Dp, searchQuery: State<String>) -> Unit, ) { val viewModel: SearchScaffoldViewModel = viewModel() + val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior() Scaffold( + modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection), topBar = { SearchableTopAppBar( title = title, actions = actions, + scrollBehavior = scrollBehavior, searchQuery = viewModel.searchQuery, ) { viewModel.searchQuery = it } }, ) { paddingValues -> Box( Modifier - .padding(paddingValues) - .fillMaxSize() + .padding(paddingValues.horizontalValues()) + .padding(top = paddingValues.calculateTopPadding()) + .fillMaxSize(), ) { - val searchQuery = remember { - derivedStateOf { viewModel.searchQuery?.text ?: "" } - } - content(searchQuery) + content( + bottomPadding = paddingValues.calculateBottomPadding(), + searchQuery = remember { + derivedStateOf { viewModel.searchQuery?.text ?: "" } + }, + ) } } } @@ -95,10 +109,12 @@ internal class SearchScaffoldViewModel : ViewModel() { var searchQuery: TextFieldValue? by mutableStateOf(null) } +@OptIn(ExperimentalMaterial3Api::class) @Composable private fun SearchableTopAppBar( title: String, actions: @Composable RowScope.() -> Unit, + scrollBehavior: TopAppBarScrollBehavior, searchQuery: TextFieldValue?, onSearchQueryChange: (TextFieldValue?) -> Unit, ) { @@ -110,13 +126,17 @@ private fun SearchableTopAppBar( actions = actions, ) } else { - SettingsTopAppBar(title) { - SearchAction { onSearchQueryChange(TextFieldValue()) } + SettingsTopAppBar(title, scrollBehavior) { + SearchAction { + scrollBehavior.collapse() + onSearchQueryChange(TextFieldValue()) + } actions() } } } +@OptIn(ExperimentalMaterial3Api::class) @Composable private fun SearchTopAppBar( query: TextFieldValue, @@ -124,21 +144,24 @@ private fun SearchTopAppBar( onClose: () -> Unit, actions: @Composable RowScope.() -> Unit = {}, ) { - TopAppBar( - title = { SearchBox(query, onQueryChange) }, - modifier = Modifier.statusBarsPadding(), - navigationIcon = { CollapseAction(onClose) }, - actions = { - if (query.text.isNotEmpty()) { - ClearAction { onQueryChange(TextFieldValue()) } - } - actions() - }, - colors = settingsTopAppBarColors(), - ) + Surface(color = SettingsTheme.colorScheme.surfaceHeader) { + TopAppBar( + title = { SearchBox(query, onQueryChange) }, + modifier = Modifier.statusBarsPadding(), + navigationIcon = { CollapseAction(onClose) }, + actions = { + if (query.text.isNotEmpty()) { + ClearAction { onQueryChange(TextFieldValue()) } + } + actions() + }, + colors = TopAppBarDefaults.smallTopAppBarColors(containerColor = Color.Transparent), + ) + } BackHandler { onClose() } } +@OptIn(ExperimentalMaterial3Api::class) @Composable private fun SearchBox(query: TextFieldValue, onQueryChange: (TextFieldValue) -> Unit) { val focusRequester = remember { FocusRequester() } @@ -184,6 +207,15 @@ private fun SearchTopAppBarPreview() { @Composable private fun SearchScaffoldPreview() { SettingsTheme { - SearchScaffold(title = "App notifications") {} + SearchScaffold(title = "App notifications") { _, _ -> + Column { + Preference(object : PreferenceModel { + override val title = "Item 1" + }) + Preference(object : PreferenceModel { + override val title = "Item 2" + }) + } + } } } diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SettingsScaffold.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SettingsScaffold.kt index 3bc3dd72d353..f4e504a954a2 100644 --- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SettingsScaffold.kt +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SettingsScaffold.kt @@ -16,13 +16,23 @@ package com.android.settingslib.spa.widget.scaffold +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.RowScope +import androidx.compose.foundation.layout.padding import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Scaffold +import androidx.compose.material3.TopAppBarDefaults import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.tooling.preview.Preview +import com.android.settingslib.spa.framework.compose.horizontalValues +import com.android.settingslib.spa.framework.compose.verticalValues import com.android.settingslib.spa.framework.theme.SettingsTheme +import com.android.settingslib.spa.widget.preference.Preference +import com.android.settingslib.spa.widget.preference.PreferenceModel /** * A [Scaffold] which content is can be full screen when needed. @@ -34,16 +44,30 @@ fun SettingsScaffold( actions: @Composable RowScope.() -> Unit = {}, content: @Composable (PaddingValues) -> Unit, ) { + val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior() Scaffold( - topBar = { SettingsTopAppBar(title, actions) }, - content = content, - ) + modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection), + topBar = { SettingsTopAppBar(title, scrollBehavior, actions) }, + ) { paddingValues -> + Box(Modifier.padding(paddingValues.horizontalValues())) { + content(paddingValues.verticalValues()) + } + } } @Preview @Composable private fun SettingsScaffoldPreview() { SettingsTheme { - SettingsScaffold(title = "Display") {} + SettingsScaffold(title = "Display") { paddingValues -> + Column(Modifier.padding(paddingValues)) { + Preference(object : PreferenceModel { + override val title = "Item 1" + }) + Preference(object : PreferenceModel { + override val title = "Item 2" + }) + } + } } } diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SettingsTopAppBar.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SettingsTopAppBar.kt index 93535203b1b9..f7cb035cbf93 100644 --- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SettingsTopAppBar.kt +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SettingsTopAppBar.kt @@ -17,41 +17,70 @@ package com.android.settingslib.spa.widget.scaffold import androidx.compose.foundation.layout.RowScope +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.asPaddingValues +import androidx.compose.foundation.layout.navigationBars import androidx.compose.foundation.layout.padding import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.LargeTopAppBar +import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text -import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBarDefaults +import androidx.compose.material3.TopAppBarScrollBehavior import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.text.style.TextOverflow +import com.android.settingslib.spa.framework.compose.horizontalValues import com.android.settingslib.spa.framework.theme.SettingsDimension import com.android.settingslib.spa.framework.theme.SettingsTheme +import com.android.settingslib.spa.framework.theme.rememberSettingsTypography @OptIn(ExperimentalMaterial3Api::class) @Composable internal fun SettingsTopAppBar( title: String, + scrollBehavior: TopAppBarScrollBehavior, actions: @Composable RowScope.() -> Unit, ) { - TopAppBar( - title = { - Text( - text = title, - modifier = Modifier.padding(SettingsDimension.itemPaddingAround), - overflow = TextOverflow.Ellipsis, - maxLines = 1, - ) - }, - navigationIcon = { NavigateBack() }, - actions = actions, - colors = settingsTopAppBarColors(), + val colorScheme = MaterialTheme.colorScheme + // TODO: Remove MaterialTheme() after top app bar color fixed in AndroidX. + MaterialTheme( + colorScheme = remember { colorScheme.copy(surface = colorScheme.background) }, + typography = rememberSettingsTypography(), + ) { + LargeTopAppBar( + title = { Title(title) }, + navigationIcon = { NavigateBack() }, + actions = actions, + colors = largeTopAppBarColors(), + scrollBehavior = scrollBehavior, + ) + } +} + +@OptIn(ExperimentalMaterial3Api::class) +internal fun TopAppBarScrollBehavior.collapse() { + with(state) { + heightOffset = heightOffsetLimit + } +} + +@Composable +private fun Title(title: String) { + Text( + text = title, + modifier = Modifier + .padding(WindowInsets.navigationBars.asPaddingValues().horizontalValues()) + .padding(SettingsDimension.itemPaddingAround), + overflow = TextOverflow.Ellipsis, + maxLines = 1, ) } @OptIn(ExperimentalMaterial3Api::class) @Composable -internal fun settingsTopAppBarColors() = TopAppBarDefaults.smallTopAppBarColors( - containerColor = SettingsTheme.colorScheme.surfaceHeader, +private fun largeTopAppBarColors() = TopAppBarDefaults.largeTopAppBarColors( + containerColor = MaterialTheme.colorScheme.background, scrolledContainerColor = SettingsTheme.colorScheme.surfaceHeader, ) diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/util/EntryHighlight.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/util/EntryHighlight.kt index 652e54de5e39..d09aec9460dd 100644 --- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/util/EntryHighlight.kt +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/util/EntryHighlight.kt @@ -16,21 +16,42 @@ package com.android.settingslib.spa.widget.util +import androidx.compose.animation.animateColorAsState +import androidx.compose.animation.core.RepeatMode +import androidx.compose.animation.core.repeatable +import androidx.compose.animation.core.tween import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable +import androidx.compose.runtime.SideEffect +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.Modifier -import androidx.compose.ui.graphics.Color import com.android.settingslib.spa.framework.common.LocalEntryDataProvider +import com.android.settingslib.spa.framework.theme.SettingsTheme @Composable internal fun EntryHighlight(UiLayoutFn: @Composable () -> Unit) { val entryData = LocalEntryDataProvider.current - val isHighlighted = rememberSaveable { entryData.isHighlighted } - val backgroundColor = - if (isHighlighted) MaterialTheme.colorScheme.surfaceVariant else Color.Transparent + var isHighlighted by rememberSaveable { mutableStateOf(false) } + SideEffect { + isHighlighted = entryData.isHighlighted + } + + val backgroundColor by animateColorAsState( + targetValue = when { + isHighlighted -> MaterialTheme.colorScheme.surfaceVariant + else -> SettingsTheme.colorScheme.background + }, + animationSpec = repeatable( + iterations = 3, + animation = tween(durationMillis = 500), + repeatMode = RepeatMode.Restart + ) + ) Box(modifier = Modifier.background(color = backgroundColor)) { UiLayoutFn() } diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/scaffold/RegularScaffoldTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/scaffold/RegularScaffoldTest.kt new file mode 100644 index 000000000000..1964c436d138 --- /dev/null +++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/scaffold/RegularScaffoldTest.kt @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2022 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.scaffold + +import androidx.compose.material3.Text +import androidx.compose.ui.test.assertIsDisplayed +import androidx.compose.ui.test.junit4.createComposeRule +import androidx.compose.ui.test.onNodeWithText +import androidx.test.ext.junit.runners.AndroidJUnit4 +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +class RegularScaffoldTest { + @get:Rule + val composeTestRule = createComposeRule() + + @Test + fun regularScaffold_titleIsDisplayed() { + composeTestRule.setContent { + RegularScaffold(title = TITLE) { + Text(text = "AAA") + Text(text = "BBB") + } + } + + composeTestRule.onNodeWithText(TITLE).assertIsDisplayed() + } + + @Test + fun regularScaffold_itemsAreDisplayed() { + composeTestRule.setContent { + RegularScaffold(title = TITLE) { + Text(text = "AAA") + Text(text = "BBB") + } + } + + composeTestRule.onNodeWithText("AAA").assertIsDisplayed() + composeTestRule.onNodeWithText("BBB").assertIsDisplayed() + } + + private companion object { + const val TITLE = "title" + } +} diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/scaffold/SearchScaffoldTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/scaffold/SearchScaffoldTest.kt index ec3379dd46ee..c3e1d544a6ab 100644 --- a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/scaffold/SearchScaffoldTest.kt +++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/scaffold/SearchScaffoldTest.kt @@ -43,7 +43,7 @@ class SearchScaffoldTest { @Test fun initialState_titleIsDisplayed() { composeTestRule.setContent { - SearchScaffold(title = TITLE) {} + SearchScaffold(title = TITLE) { _, _ -> } } composeTestRule.onNodeWithText(TITLE).assertIsDisplayed() @@ -116,7 +116,7 @@ class SearchScaffoldTest { private fun setContent(): State<String> { lateinit var actualSearchQuery: State<String> composeTestRule.setContent { - SearchScaffold(title = TITLE) { searchQuery -> + SearchScaffold(title = TITLE) { _, searchQuery -> SideEffect { actualSearchQuery = searchQuery } diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/scaffold/SettingsPagerKtTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/scaffold/SettingsPagerTest.kt index 0c84eac45cb7..0c745d5d5b3d 100644 --- a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/scaffold/SettingsPagerKtTest.kt +++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/scaffold/SettingsPagerTest.kt @@ -16,7 +16,6 @@ package com.android.settingslib.spa.widget.scaffold -import androidx.compose.runtime.Composable import androidx.compose.ui.test.assertIsDisplayed import androidx.compose.ui.test.assertIsNotDisplayed import androidx.compose.ui.test.assertIsNotSelected @@ -31,15 +30,13 @@ import org.junit.Test import org.junit.runner.RunWith @RunWith(AndroidJUnit4::class) -class SettingsPagerKtTest { +class SettingsPagerTest { @get:Rule val composeTestRule = createComposeRule() @Test fun twoPage_initialState() { - composeTestRule.setContent { - TestTwoPage() - } + setTwoPagesContent() composeTestRule.onNodeWithText("Personal").assertIsSelected() composeTestRule.onNodeWithText("Page 0").assertIsDisplayed() @@ -49,9 +46,7 @@ class SettingsPagerKtTest { @Test fun twoPage_afterSwitch() { - composeTestRule.setContent { - TestTwoPage() - } + setTwoPagesContent() composeTestRule.onNodeWithText("Work").performClick() @@ -73,11 +68,12 @@ class SettingsPagerKtTest { composeTestRule.onNodeWithText("Page 0").assertIsDisplayed() composeTestRule.onNodeWithText("Page 1").assertDoesNotExist() } -} -@Composable -private fun TestTwoPage() { - SettingsPager(listOf("Personal", "Work")) { - SettingsTitle(title = "Page $it") + private fun setTwoPagesContent() { + composeTestRule.setContent { + SettingsPager(listOf("Personal", "Work")) { + SettingsTitle(title = "Page $it") + } + } } } diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/scaffold/SettingsScaffoldTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/scaffold/SettingsScaffoldTest.kt new file mode 100644 index 000000000000..f04240485386 --- /dev/null +++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/scaffold/SettingsScaffoldTest.kt @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2022 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.scaffold + +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.material3.Text +import androidx.compose.runtime.SideEffect +import androidx.compose.ui.test.assertIsDisplayed +import androidx.compose.ui.test.junit4.createComposeRule +import androidx.compose.ui.test.onNodeWithText +import androidx.compose.ui.unit.LayoutDirection +import androidx.compose.ui.unit.dp +import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.google.common.truth.Truth.assertThat +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +class SettingsScaffoldTest { + @get:Rule + val composeTestRule = createComposeRule() + + @Test + fun settingsScaffold_titleIsDisplayed() { + composeTestRule.setContent { + SettingsScaffold(title = TITLE) { + Text(text = "AAA") + Text(text = "BBB") + } + } + + composeTestRule.onNodeWithText(TITLE).assertIsDisplayed() + } + + @Test + fun settingsScaffold_itemsAreDisplayed() { + composeTestRule.setContent { + SettingsScaffold(title = TITLE) { + Text(text = "AAA") + Text(text = "BBB") + } + } + + composeTestRule.onNodeWithText("AAA").assertIsDisplayed() + composeTestRule.onNodeWithText("BBB").assertIsDisplayed() + } + + @Test + fun settingsScaffold_noHorizontalPadding() { + lateinit var actualPaddingValues: PaddingValues + + composeTestRule.setContent { + SettingsScaffold(title = TITLE) { paddingValues -> + SideEffect { + actualPaddingValues = paddingValues + } + } + } + + assertThat(actualPaddingValues.calculateLeftPadding(LayoutDirection.Ltr)).isEqualTo(0.dp) + assertThat(actualPaddingValues.calculateLeftPadding(LayoutDirection.Rtl)).isEqualTo(0.dp) + assertThat(actualPaddingValues.calculateRightPadding(LayoutDirection.Ltr)).isEqualTo(0.dp) + assertThat(actualPaddingValues.calculateRightPadding(LayoutDirection.Rtl)).isEqualTo(0.dp) + } + + private companion object { + const val TITLE = "title" + } +} diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/ApplicationInfos.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/ApplicationInfos.kt index c1ac5d473dba..8954d22f45cc 100644 --- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/ApplicationInfos.kt +++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/ApplicationInfos.kt @@ -35,6 +35,9 @@ val ApplicationInfo.userHandle: UserHandle /** Checks whether a flag is associated with the application. */ fun ApplicationInfo.hasFlag(flag: Int): Boolean = (flags and flag) > 0 +/** Checks whether the application is currently installed. */ +val ApplicationInfo.installed: Boolean get() = hasFlag(ApplicationInfo.FLAG_INSTALLED) + /** Checks whether the application is disabled until used. */ val ApplicationInfo.isDisabledUntilUsed: Boolean get() = enabledSetting == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppList.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppList.kt index 408b9df5e3ef..3cd8378b8960 100644 --- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppList.kt +++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppList.kt @@ -25,12 +25,12 @@ import androidx.compose.runtime.collectAsState import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.Dp import androidx.lifecycle.viewmodel.compose.viewModel import com.android.settingslib.spa.framework.compose.LogCompositions import com.android.settingslib.spa.framework.compose.TimeMeasurer.Companion.rememberTimeMeasurer import com.android.settingslib.spa.framework.compose.rememberLazyListStateAndHideKeyboardWhenStartScroll import com.android.settingslib.spa.framework.compose.toState -import com.android.settingslib.spa.framework.theme.SettingsDimension import com.android.settingslib.spa.widget.ui.PlaceholderTitle import com.android.settingslib.spaprivileged.R import com.android.settingslib.spaprivileged.model.app.AppListConfig @@ -55,10 +55,11 @@ internal fun <T : AppRecord> AppList( option: State<Int>, searchQuery: State<String>, appItem: @Composable (itemState: AppListItemModel<T>) -> Unit, + bottomPadding: Dp, ) { LogCompositions(TAG, appListConfig.userId.toString()) val appListData = loadAppEntries(appListConfig, listModel, showSystem, option, searchQuery) - AppListWidget(appListData, listModel, appItem) + AppListWidget(appListData, listModel, appItem, bottomPadding) } @Composable @@ -66,6 +67,7 @@ private fun <T : AppRecord> AppListWidget( appListData: State<AppListData<T>?>, listModel: AppListModel<T>, appItem: @Composable (itemState: AppListItemModel<T>) -> Unit, + bottomPadding: Dp, ) { val timeMeasurer = rememberTimeMeasurer(TAG) appListData.value?.let { (list, option) -> @@ -77,7 +79,7 @@ private fun <T : AppRecord> AppListWidget( LazyColumn( modifier = Modifier.fillMaxSize(), state = rememberLazyListStateAndHideKeyboardWhenStartScroll(), - contentPadding = PaddingValues(bottom = SettingsDimension.itemPaddingVertical), + contentPadding = PaddingValues(bottom = bottomPadding), ) { items(count = list.size, key = { option to list[it].record.app.packageName }) { val appEntry = list[it] diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppListPage.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppListPage.kt index 99376b0005e4..29533679d9c1 100644 --- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppListPage.kt +++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppListPage.kt @@ -52,7 +52,7 @@ fun <T : AppRecord> AppListPage( actions = { ShowSystemAction(showSystem.value) { showSystem.value = it } }, - ) { searchQuery -> + ) { bottomPadding, searchQuery -> WorkProfilePager(primaryUserOnly) { userInfo -> Column(Modifier.fillMaxSize()) { val options = remember { listModel.getSpinnerOptions() } @@ -68,6 +68,7 @@ fun <T : AppRecord> AppListPage( option = selectedOption, searchQuery = searchQuery, appItem = appItem, + bottomPadding = bottomPadding, ) } } diff --git a/packages/SettingsLib/src/com/android/settingslib/mobile/dataservice/DataServiceUtils.java b/packages/SettingsLib/src/com/android/settingslib/mobile/dataservice/DataServiceUtils.java index 03d9f2db01f2..30d382023b5d 100644 --- a/packages/SettingsLib/src/com/android/settingslib/mobile/dataservice/DataServiceUtils.java +++ b/packages/SettingsLib/src/com/android/settingslib/mobile/dataservice/DataServiceUtils.java @@ -357,5 +357,12 @@ public class DataServiceUtils { * {@link SubscriptionManager#getDefaultSubscriptionId()}. */ public static final String COLUMN_IS_DEFAULT_SUBSCRIPTION = "isDefaultSubscription"; + + /** + * The name of the active data subscription state column, see + * {@link SubscriptionManager#getActiveDataSubscriptionId()}. + */ + public static final String COLUMN_IS_ACTIVE_DATA_SUBSCRIPTION = + "isActiveDataSubscriptionId"; } } diff --git a/packages/SettingsLib/src/com/android/settingslib/mobile/dataservice/SubscriptionInfoEntity.java b/packages/SettingsLib/src/com/android/settingslib/mobile/dataservice/SubscriptionInfoEntity.java index 329bd9bfb9e7..23566f760444 100644 --- a/packages/SettingsLib/src/com/android/settingslib/mobile/dataservice/SubscriptionInfoEntity.java +++ b/packages/SettingsLib/src/com/android/settingslib/mobile/dataservice/SubscriptionInfoEntity.java @@ -42,7 +42,7 @@ public class SubscriptionInfoEntity { boolean isUsableSubscription, boolean isActiveSubscriptionId, boolean isAvailableSubscription, boolean isDefaultVoiceSubscription, boolean isDefaultSmsSubscription, boolean isDefaultDataSubscription, - boolean isDefaultSubscription) { + boolean isDefaultSubscription, boolean isActiveDataSubscriptionId) { this.subId = subId; this.simSlotIndex = simSlotIndex; this.carrierId = carrierId; @@ -72,6 +72,7 @@ public class SubscriptionInfoEntity { this.isDefaultSmsSubscription = isDefaultSmsSubscription; this.isDefaultDataSubscription = isDefaultDataSubscription; this.isDefaultSubscription = isDefaultSubscription; + this.isActiveDataSubscriptionId = isActiveDataSubscriptionId; } @PrimaryKey @@ -165,6 +166,9 @@ public class SubscriptionInfoEntity { @ColumnInfo(name = DataServiceUtils.SubscriptionInfoData.COLUMN_IS_DEFAULT_SUBSCRIPTION) public boolean isDefaultSubscription; + @ColumnInfo(name = DataServiceUtils.SubscriptionInfoData.COLUMN_IS_ACTIVE_DATA_SUBSCRIPTION) + public boolean isActiveDataSubscriptionId; + public int getSubId() { return Integer.valueOf(subId); } @@ -213,6 +217,7 @@ public class SubscriptionInfoEntity { result = 31 * result + Boolean.hashCode(isDefaultSmsSubscription); result = 31 * result + Boolean.hashCode(isDefaultDataSubscription); result = 31 * result + Boolean.hashCode(isDefaultSubscription); + result = 31 * result + Boolean.hashCode(isActiveDataSubscriptionId); return result; } @@ -254,7 +259,8 @@ public class SubscriptionInfoEntity { && isDefaultVoiceSubscription == info.isDefaultVoiceSubscription && isDefaultSmsSubscription == info.isDefaultSmsSubscription && isDefaultDataSubscription == info.isDefaultDataSubscription - && isDefaultSubscription == info.isDefaultSubscription; + && isDefaultSubscription == info.isDefaultSubscription + && isActiveDataSubscriptionId == info.isActiveDataSubscriptionId; } public String toString() { @@ -317,6 +323,8 @@ public class SubscriptionInfoEntity { .append(isDefaultDataSubscription) .append(", isDefaultSubscription = ") .append(isDefaultSubscription) + .append(", isActiveDataSubscriptionId = ") + .append(isActiveDataSubscriptionId) .append(")}"); return builder.toString(); } diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml index 92ef3f8201cb..159323a5b557 100644 --- a/packages/SystemUI/res/layout/status_bar_expanded.xml +++ b/packages/SystemUI/res/layout/status_bar_expanded.xml @@ -42,12 +42,6 @@ android:clipToPadding="false" android:clipChildren="false"> - <ViewStub - android:id="@+id/qs_header_stub" - android:layout_height="wrap_content" - android:layout_width="match_parent" - /> - <include layout="@layout/keyguard_status_view" android:visibility="gone"/> @@ -69,6 +63,15 @@ systemui:layout_constraintBottom_toBottomOf="parent" /> + <!-- This view should be after qs_frame so touches are dispatched first to it. That gives + it a chance to capture clicks before the NonInterceptingScrollView disallows all + intercepts --> + <ViewStub + android:id="@+id/qs_header_stub" + android:layout_height="wrap_content" + android:layout_width="match_parent" + /> + <androidx.constraintlayout.widget.Guideline android:id="@+id/qs_edge_guideline" android:layout_width="wrap_content" diff --git a/packages/SystemUI/src-debug/com/android/systemui/flags/FlagsModule.kt b/packages/SystemUI/src-debug/com/android/systemui/flags/FlagsModule.kt index bb3df8f0358a..7b216017df7d 100644 --- a/packages/SystemUI/src-debug/com/android/systemui/flags/FlagsModule.kt +++ b/packages/SystemUI/src-debug/com/android/systemui/flags/FlagsModule.kt @@ -18,17 +18,15 @@ package com.android.systemui.flags import android.content.Context import android.os.Handler -import com.android.internal.statusbar.IStatusBarService import com.android.systemui.dagger.qualifiers.Main -import com.android.systemui.flags.FeatureFlagsDebug.ALL_FLAGS import com.android.systemui.util.settings.SettingsUtilModule import dagger.Binds import dagger.Module import dagger.Provides -import javax.inject.Named @Module(includes = [ FeatureFlagsDebugStartableModule::class, + FlagsCommonModule::class, ServerFlagReaderModule::class, SettingsUtilModule::class, ]) @@ -43,20 +41,5 @@ abstract class FlagsModule { fun provideFlagManager(context: Context, @Main handler: Handler): FlagManager { return FlagManager(context, handler) } - - @JvmStatic - @Provides - @Named(ALL_FLAGS) - fun providesAllFlags(): Map<Int, Flag<*>> = Flags.collectFlags() - - @JvmStatic - @Provides - fun providesRestarter(barService: IStatusBarService): Restarter { - return object: Restarter { - override fun restart() { - barService.restart() - } - } - } } } diff --git a/packages/SystemUI/src-release/com/android/systemui/flags/FlagsModule.kt b/packages/SystemUI/src-release/com/android/systemui/flags/FlagsModule.kt index 0f7e732fceb1..aef887667527 100644 --- a/packages/SystemUI/src-release/com/android/systemui/flags/FlagsModule.kt +++ b/packages/SystemUI/src-release/com/android/systemui/flags/FlagsModule.kt @@ -16,29 +16,15 @@ package com.android.systemui.flags -import com.android.internal.statusbar.IStatusBarService import dagger.Binds import dagger.Module -import dagger.Provides @Module(includes = [ FeatureFlagsReleaseStartableModule::class, + FlagsCommonModule::class, ServerFlagReaderModule::class ]) abstract class FlagsModule { @Binds abstract fun bindsFeatureFlagRelease(impl: FeatureFlagsRelease): FeatureFlags - - @Module - companion object { - @JvmStatic - @Provides - fun providesRestarter(barService: IStatusBarService): Restarter { - return object: Restarter { - override fun restart() { - barService.restart() - } - } - } - } } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java index 3273d7429d49..b0e612530fb3 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java @@ -60,6 +60,8 @@ import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.doze.DozeReceiver; import com.android.systemui.dump.DumpManager; +import com.android.systemui.flags.FeatureFlags; +import com.android.systemui.flags.Flags; import com.android.systemui.keyguard.ScreenLifecycle; import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.statusbar.StatusBarStateController; @@ -119,6 +121,7 @@ public class UdfpsController implements DozeReceiver { @NonNull private final SystemUIDialogManager mDialogManager; @NonNull private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; @NonNull private final VibratorHelper mVibrator; + @NonNull private final FeatureFlags mFeatureFlags; @NonNull private final FalsingManager mFalsingManager; @NonNull private final PowerManager mPowerManager; @NonNull private final AccessibilityManager mAccessibilityManager; @@ -202,6 +205,10 @@ public class UdfpsController implements DozeReceiver { @Override public void showUdfpsOverlay(long requestId, int sensorId, int reason, @NonNull IUdfpsOverlayControllerCallback callback) { + if (mFeatureFlags.isEnabled(Flags.NEW_UDFPS_OVERLAY)) { + return; + } + mFgExecutor.execute(() -> UdfpsController.this.showUdfpsOverlay( new UdfpsControllerOverlay(mContext, mFingerprintManager, mInflater, mWindowManager, mAccessibilityManager, mStatusBarStateController, @@ -217,6 +224,10 @@ public class UdfpsController implements DozeReceiver { @Override public void hideUdfpsOverlay(int sensorId) { + if (mFeatureFlags.isEnabled(Flags.NEW_UDFPS_OVERLAY)) { + return; + } + mFgExecutor.execute(() -> { if (mKeyguardUpdateMonitor.isFingerprintDetectionRunning()) { // if we get here, we expect keyguardUpdateMonitor's fingerprintRunningState @@ -590,6 +601,7 @@ public class UdfpsController implements DozeReceiver { @NonNull StatusBarKeyguardViewManager statusBarKeyguardViewManager, @NonNull DumpManager dumpManager, @NonNull KeyguardUpdateMonitor keyguardUpdateMonitor, + @NonNull FeatureFlags featureFlags, @NonNull FalsingManager falsingManager, @NonNull PowerManager powerManager, @NonNull AccessibilityManager accessibilityManager, @@ -625,6 +637,7 @@ public class UdfpsController implements DozeReceiver { mDumpManager = dumpManager; mDialogManager = dialogManager; mKeyguardUpdateMonitor = keyguardUpdateMonitor; + mFeatureFlags = featureFlags; mFalsingManager = falsingManager; mPowerManager = powerManager; mAccessibilityManager = accessibilityManager; diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsOverlay.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsOverlay.kt index 6e78f3d3d6aa..142642a2411f 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsOverlay.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsOverlay.kt @@ -19,26 +19,40 @@ package com.android.systemui.biometrics import android.annotation.SuppressLint import android.content.Context import android.graphics.PixelFormat +import android.graphics.Point import android.graphics.Rect +import android.hardware.biometrics.BiometricOverlayConstants import android.hardware.fingerprint.FingerprintManager import android.hardware.fingerprint.FingerprintSensorPropertiesInternal import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback +import android.hardware.fingerprint.IUdfpsOverlay import android.os.Handler +import android.provider.Settings import android.view.MotionEvent -import android.view.View import android.view.WindowManager import android.view.WindowManager.LayoutParams.INPUT_FEATURE_SPY import com.android.keyguard.KeyguardUpdateMonitor import com.android.systemui.CoreStartable import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Main +import com.android.systemui.flags.FeatureFlags +import com.android.systemui.flags.Flags import com.android.systemui.util.concurrency.DelayableExecutor import com.android.systemui.util.concurrency.Execution -import java.util.* +import java.util.Optional import java.util.concurrent.Executor import javax.inject.Inject +import kotlin.math.cos +import kotlin.math.pow +import kotlin.math.sin private const val TAG = "UdfpsOverlay" +const val SETTING_OVERLAY_DEBUG = "udfps_overlay_debug" + +// Number of sensor points needed inside ellipse for good overlap +private const val NEEDED_POINTS = 2 + @SuppressLint("ClickableViewAccessibility") @SysUISingleton class UdfpsOverlay @@ -51,10 +65,11 @@ constructor( private val handler: Handler, private val biometricExecutor: Executor, private val alternateTouchProvider: Optional<AlternateUdfpsTouchProvider>, - private val fgExecutor: DelayableExecutor, + @Main private val fgExecutor: DelayableExecutor, private val keyguardUpdateMonitor: KeyguardUpdateMonitor, private val authController: AuthController, - private val udfpsLogger: UdfpsLogger + private val udfpsLogger: UdfpsLogger, + private var featureFlags: FeatureFlags ) : CoreStartable { /** The view, when [isShowing], or null. */ @@ -64,7 +79,11 @@ constructor( private var requestId: Long = 0 private var onFingerDown = false val size = windowManager.maximumWindowMetrics.bounds + val udfpsProps: MutableList<FingerprintSensorPropertiesInternal> = mutableListOf() + var points: Array<Point> = emptyArray() + var processedMotionEvent = false + var isShowing = false private var params: UdfpsOverlayParams = UdfpsOverlayParams() @@ -87,41 +106,57 @@ constructor( inputFeatures = INPUT_FEATURE_SPY } - fun onTouch(v: View, event: MotionEvent): Boolean { - val view = v as UdfpsOverlayView + fun onTouch(event: MotionEvent): Boolean { + val view = overlayView!! return when (event.action) { MotionEvent.ACTION_DOWN, MotionEvent.ACTION_MOVE -> { onFingerDown = true if (!view.isDisplayConfigured && alternateTouchProvider.isPresent) { - biometricExecutor.execute { - alternateTouchProvider - .get() - .onPointerDown( - requestId, - event.x.toInt(), - event.y.toInt(), - event.touchMinor, - event.touchMajor - ) - } - fgExecutor.execute { - if (keyguardUpdateMonitor.isFingerprintDetectionRunning) { - keyguardUpdateMonitor.onUdfpsPointerDown(requestId.toInt()) + view.processMotionEvent(event) + + val goodOverlap = + if (featureFlags.isEnabled(Flags.NEW_ELLIPSE_DETECTION)) { + isGoodEllipseOverlap(event) + } else { + isGoodCentroidOverlap(event) } - } - view.configureDisplay { - biometricExecutor.execute { alternateTouchProvider.get().onUiReady() } + if (!processedMotionEvent && goodOverlap) { + biometricExecutor.execute { + alternateTouchProvider + .get() + .onPointerDown( + requestId, + event.rawX.toInt(), + event.rawY.toInt(), + event.touchMinor, + event.touchMajor + ) + } + fgExecutor.execute { + if (keyguardUpdateMonitor.isFingerprintDetectionRunning) { + keyguardUpdateMonitor.onUdfpsPointerDown(requestId.toInt()) + } + + view.configureDisplay { + biometricExecutor.execute { + alternateTouchProvider.get().onUiReady() + } + } + + processedMotionEvent = true + } } - } + view.invalidate() + } true } MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> { - if (onFingerDown && alternateTouchProvider.isPresent) { + if (processedMotionEvent && alternateTouchProvider.isPresent) { biometricExecutor.execute { alternateTouchProvider.get().onPointerUp(requestId) } @@ -130,43 +165,105 @@ constructor( keyguardUpdateMonitor.onUdfpsPointerUp(requestId.toInt()) } } + + processedMotionEvent = false } - onFingerDown = false + if (view.isDisplayConfigured) { view.unconfigureDisplay() } + view.invalidate() true } else -> false } } - fun show(requestId: Long): Boolean { + fun isGoodEllipseOverlap(event: MotionEvent): Boolean { + return points.count { checkPoint(event, it) } >= NEEDED_POINTS + } + + fun isGoodCentroidOverlap(event: MotionEvent): Boolean { + return params.sensorBounds.contains(event.rawX.toInt(), event.rawY.toInt()) + } + + fun checkPoint(event: MotionEvent, point: Point): Boolean { + // Calculate if sensor point is within ellipse + // Formula: ((cos(o)(xE - xS) + sin(o)(yE - yS))^2 / a^2) + ((sin(o)(xE - xS) + cos(o)(yE - + // yS))^2 / b^2) <= 1 + val a: Float = cos(event.orientation) * (point.x - event.rawX) + val b: Float = sin(event.orientation) * (point.y - event.rawY) + val c: Float = sin(event.orientation) * (point.x - event.rawX) + val d: Float = cos(event.orientation) * (point.y - event.rawY) + val result = + (a + b).pow(2) / (event.touchMinor / 2).pow(2) + + (c - d).pow(2) / (event.touchMajor / 2).pow(2) + + return result <= 1 + } + + fun show(requestId: Long) { + if (!featureFlags.isEnabled(Flags.NEW_UDFPS_OVERLAY)) { + return + } + this.requestId = requestId - if (overlayView == null && alternateTouchProvider.isPresent) { - UdfpsOverlayView(context, null).let { - it.overlayParams = params - it.setUdfpsDisplayMode( - UdfpsDisplayMode(context, execution, authController, udfpsLogger) - ) - it.setOnTouchListener { v, event -> onTouch(v, event) } - overlayView = it + fgExecutor.execute { + if (overlayView == null && alternateTouchProvider.isPresent) { + UdfpsOverlayView(context, null).let { + it.overlayParams = params + it.setUdfpsDisplayMode( + UdfpsDisplayMode(context, execution, authController, udfpsLogger) + ) + it.setOnTouchListener { _, event -> onTouch(event) } + it.sensorPoints = points + it.debugOverlay = + Settings.Global.getInt( + context.contentResolver, + SETTING_OVERLAY_DEBUG, + 0 /* def */ + ) != 0 + overlayView = it + } + windowManager.addView(overlayView, coreLayoutParams) + isShowing = true } - windowManager.addView(overlayView, coreLayoutParams) - return true } - - return false } fun hide() { - overlayView?.apply { - windowManager.removeView(this) - setOnTouchListener(null) + if (!featureFlags.isEnabled(Flags.NEW_UDFPS_OVERLAY)) { + return } - overlayView = null + fgExecutor.execute { + if (overlayView != null && isShowing && alternateTouchProvider.isPresent) { + if (processedMotionEvent) { + biometricExecutor.execute { + alternateTouchProvider.get().onPointerUp(requestId) + } + fgExecutor.execute { + if (keyguardUpdateMonitor.isFingerprintDetectionRunning) { + keyguardUpdateMonitor.onUdfpsPointerUp(requestId.toInt()) + } + } + } + + if (overlayView!!.isDisplayConfigured) { + overlayView!!.unconfigureDisplay() + } + + overlayView?.apply { + windowManager.removeView(this) + setOnTouchListener(null) + } + + isShowing = false + overlayView = null + processedMotionEvent = false + } + } } @Override @@ -180,6 +277,18 @@ constructor( } } ) + + fingerprintManager?.setUdfpsOverlay( + object : IUdfpsOverlay.Stub() { + override fun show( + requestId: Long, + sensorId: Int, + @BiometricOverlayConstants.ShowReason reason: Int + ) = show(requestId) + + override fun hide(sensorId: Int) = hide() + } + ) } private fun handleAllFingerprintAuthenticatorsRegistered( @@ -201,6 +310,24 @@ constructor( naturalDisplayHeight = size.height(), scaleFactor = 1f ) + + val sensorX = params.sensorBounds.centerX() + val sensorY = params.sensorBounds.centerY() + val cornerOffset: Int = params.sensorBounds.width() / 4 + val sideOffset: Int = params.sensorBounds.width() / 3 + + points = + arrayOf( + Point(sensorX - cornerOffset, sensorY - cornerOffset), + Point(sensorX, sensorY - sideOffset), + Point(sensorX + cornerOffset, sensorY - cornerOffset), + Point(sensorX - sideOffset, sensorY), + Point(sensorX, sensorY), + Point(sensorX + sideOffset, sensorY), + Point(sensorX - cornerOffset, sensorY + cornerOffset), + Point(sensorX, sensorY + sideOffset), + Point(sensorX + cornerOffset, sensorY + cornerOffset) + ) } } } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsOverlayView.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsOverlayView.kt index d37133239531..4e6a06b1c44b 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsOverlayView.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsOverlayView.kt @@ -20,26 +20,41 @@ import android.content.Context import android.graphics.Canvas import android.graphics.Color import android.graphics.Paint +import android.graphics.Point import android.graphics.RectF import android.util.AttributeSet +import android.view.MotionEvent import android.widget.FrameLayout private const val TAG = "UdfpsOverlayView" +private const val POINT_SIZE = 10f class UdfpsOverlayView(context: Context, attrs: AttributeSet?) : FrameLayout(context, attrs) { - - private val sensorRect = RectF() var overlayParams = UdfpsOverlayParams() private var mUdfpsDisplayMode: UdfpsDisplayMode? = null + var debugOverlay = false + var overlayPaint = Paint() var sensorPaint = Paint() + var touchPaint = Paint() + var pointPaint = Paint() val centerPaint = Paint() + var oval = RectF() + /** True after the call to [configureDisplay] and before the call to [unconfigureDisplay]. */ var isDisplayConfigured: Boolean = false private set + var touchX: Float = 0f + var touchY: Float = 0f + var touchMinor: Float = 0f + var touchMajor: Float = 0f + var touchOrientation: Double = 0.0 + + var sensorPoints: Array<Point>? = null + init { this.setWillNotDraw(false) } @@ -47,24 +62,60 @@ class UdfpsOverlayView(context: Context, attrs: AttributeSet?) : FrameLayout(con override fun onAttachedToWindow() { super.onAttachedToWindow() - overlayPaint.color = Color.argb(120, 255, 0, 0) + overlayPaint.color = Color.argb(100, 255, 0, 0) overlayPaint.style = Paint.Style.FILL + touchPaint.color = Color.argb(200, 255, 255, 255) + touchPaint.style = Paint.Style.FILL + sensorPaint.color = Color.argb(150, 134, 204, 255) sensorPaint.style = Paint.Style.FILL + + pointPaint.color = Color.WHITE + pointPaint.style = Paint.Style.FILL } override fun onDraw(canvas: Canvas) { super.onDraw(canvas) - canvas.drawRect(overlayParams.overlayBounds, overlayPaint) - canvas.drawRect(overlayParams.sensorBounds, sensorPaint) + if (debugOverlay) { + // Draw overlay and sensor bounds + canvas.drawRect(overlayParams.overlayBounds, overlayPaint) + canvas.drawRect(overlayParams.sensorBounds, sensorPaint) + } + + // Draw sensor circle canvas.drawCircle( overlayParams.sensorBounds.exactCenterX(), overlayParams.sensorBounds.exactCenterY(), overlayParams.sensorBounds.width().toFloat() / 2, centerPaint ) + + if (debugOverlay) { + // Draw Points + sensorPoints?.forEach { + canvas.drawCircle(it.x.toFloat(), it.y.toFloat(), POINT_SIZE, pointPaint) + } + + // Draw touch oval + canvas.save() + canvas.rotate(Math.toDegrees(touchOrientation).toFloat(), touchX, touchY) + + oval.setEmpty() + oval.set( + touchX - touchMinor / 2, + touchY + touchMajor / 2, + touchX + touchMinor / 2, + touchY - touchMajor / 2 + ) + + canvas.drawOval(oval, touchPaint) + + // Draw center point + canvas.drawCircle(touchX, touchY, POINT_SIZE, centerPaint) + canvas.restore() + } } fun setUdfpsDisplayMode(udfpsDisplayMode: UdfpsDisplayMode?) { @@ -80,4 +131,12 @@ class UdfpsOverlayView(context: Context, attrs: AttributeSet?) : FrameLayout(con isDisplayConfigured = false mUdfpsDisplayMode?.disable(null /* onDisabled */) } + + fun processMotionEvent(event: MotionEvent) { + touchX = event.rawX + touchY = event.rawY + touchMinor = event.touchMinor + touchMajor = event.touchMajor + touchOrientation = event.orientation.toDouble() + } } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsShell.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsShell.kt index 75640b787a62..da50f1c94f29 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsShell.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsShell.kt @@ -62,7 +62,6 @@ class UdfpsShell @Inject constructor( if (args.size == 1 && args[0] == "hide") { hideOverlay() } else if (args.size == 2 && args[0] == "udfpsOverlay" && args[1] == "show") { - hideOverlay() showUdfpsOverlay() } else if (args.size == 2 && args[0] == "udfpsOverlay" && args[1] == "hide") { hideUdfpsOverlay() diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java index e47e636fa445..6db562107357 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java @@ -84,6 +84,7 @@ import com.android.systemui.statusbar.policy.dagger.SmartRepliesInflationModule; import com.android.systemui.statusbar.policy.dagger.StatusBarPolicyModule; import com.android.systemui.statusbar.window.StatusBarWindowModule; import com.android.systemui.telephony.data.repository.TelephonyRepositoryModule; +import com.android.systemui.temporarydisplay.dagger.TemporaryDisplayModule; import com.android.systemui.tuner.dagger.TunerModule; import com.android.systemui.unfold.SysUIUnfoldModule; import com.android.systemui.user.UserModule; @@ -150,6 +151,7 @@ import dagger.Provides; SysUIConcurrencyModule.class, SysUIUnfoldModule.class, TelephonyRepositoryModule.class, + TemporaryDisplayModule.class, TunerModule.class, UserModule.class, UtilModule.class, diff --git a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebug.java b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebug.java index 3adeeac2e4d4..1f061e9ff1c6 100644 --- a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebug.java +++ b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebug.java @@ -21,6 +21,7 @@ import static com.android.systemui.flags.FlagManager.ACTION_SET_FLAG; import static com.android.systemui.flags.FlagManager.EXTRA_FLAGS; import static com.android.systemui.flags.FlagManager.EXTRA_ID; import static com.android.systemui.flags.FlagManager.EXTRA_VALUE; +import static com.android.systemui.flags.FlagsCommonModule.ALL_FLAGS; import static java.util.Objects.requireNonNull; @@ -59,20 +60,20 @@ import javax.inject.Named; * * Flags can be set (or unset) via the following adb command: * - * adb shell cmd statusbar flag <id> <on|off|toggle|erase> + * adb shell cmd statusbar flag <id> <on|off|toggle|erase> * - * Alternatively, you can change flags via a broadcast intent: + * Alternatively, you can change flags via a broadcast intent: * - * adb shell am broadcast -a com.android.systemui.action.SET_FLAG --ei id <id> [--ez value <0|1>] + * adb shell am broadcast -a com.android.systemui.action.SET_FLAG --ei id <id> [--ez value <0|1>] * * To restore a flag back to its default, leave the `--ez value <0|1>` off of the command. */ @SysUISingleton public class FeatureFlagsDebug implements FeatureFlags { static final String TAG = "SysUIFlags"; - static final String ALL_FLAGS = "all_flags"; private final FlagManager mFlagManager; + private final Context mContext; private final SecureSettings mSecureSettings; private final Resources mResources; private final SystemPropertiesHelper mSystemProperties; @@ -83,6 +84,14 @@ public class FeatureFlagsDebug implements FeatureFlags { private final Map<Integer, String> mStringFlagCache = new TreeMap<>(); private final Restarter mRestarter; + private final ServerFlagReader.ChangeListener mOnPropertiesChanged = + new ServerFlagReader.ChangeListener() { + @Override + public void onChange() { + mRestarter.restart(); + } + }; + @Inject public FeatureFlagsDebug( FlagManager flagManager, @@ -93,23 +102,28 @@ public class FeatureFlagsDebug implements FeatureFlags { DeviceConfigProxy deviceConfigProxy, ServerFlagReader serverFlagReader, @Named(ALL_FLAGS) Map<Integer, Flag<?>> allFlags, - Restarter barService) { + Restarter restarter) { mFlagManager = flagManager; + mContext = context; mSecureSettings = secureSettings; mResources = resources; mSystemProperties = systemProperties; mDeviceConfigProxy = deviceConfigProxy; mServerFlagReader = serverFlagReader; mAllFlags = allFlags; - mRestarter = barService; + mRestarter = restarter; + } + /** Call after construction to setup listeners. */ + void init() { IntentFilter filter = new IntentFilter(); filter.addAction(ACTION_SET_FLAG); filter.addAction(ACTION_GET_FLAGS); - flagManager.setOnSettingsChangedAction(this::restartSystemUI); - flagManager.setClearCacheAction(this::removeFromCache); - context.registerReceiver(mReceiver, filter, null, null, + mFlagManager.setOnSettingsChangedAction(this::restartSystemUI); + mFlagManager.setClearCacheAction(this::removeFromCache); + mContext.registerReceiver(mReceiver, filter, null, null, Context.RECEIVER_EXPORTED_UNAUDITED); + mServerFlagReader.listenForChanges(mAllFlags.values(), mOnPropertiesChanged); } @Override @@ -196,7 +210,7 @@ public class FeatureFlagsDebug implements FeatureFlags { return mStringFlagCache.get(id); } - /** Specific override for Boolean flags that checks against the teamfood list.*/ + /** Specific override for Boolean flags that checks against the teamfood list. */ private boolean readFlagValue(int id, boolean defaultValue) { Boolean result = readBooleanFlagOverride(id); boolean hasServerOverride = mServerFlagReader.hasOverride(id); @@ -273,6 +287,7 @@ public class FeatureFlagsDebug implements FeatureFlags { private void dispatchListenersAndMaybeRestart(int id, Consumer<Boolean> restartAction) { mFlagManager.dispatchListenersAndMaybeRestart(id, restartAction); } + /** Works just like {@link #eraseFlag(int)} except that it doesn't restart SystemUI. */ private void eraseInternal(int id) { // We can't actually "erase" things from sysprops, but we can set them to empty! @@ -358,7 +373,7 @@ public class FeatureFlagsDebug implements FeatureFlags { } } - Bundle extras = getResultExtras(true); + Bundle extras = getResultExtras(true); if (extras != null) { extras.putParcelableArrayList(EXTRA_FLAGS, pFlags); } diff --git a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebugStartable.kt b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebugStartable.kt index 560dcbd78c42..62713348c789 100644 --- a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebugStartable.kt +++ b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebugStartable.kt @@ -31,7 +31,7 @@ constructor( dumpManager: DumpManager, private val commandRegistry: CommandRegistry, private val flagCommand: FlagCommand, - featureFlags: FeatureFlags + private val featureFlags: FeatureFlagsDebug ) : CoreStartable { init { @@ -41,6 +41,7 @@ constructor( } override fun start() { + featureFlags.init() commandRegistry.registerCommand(FlagCommand.FLAG_COMMAND) { flagCommand } } } diff --git a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsRelease.java b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsRelease.java index 40a8a1a9ef01..30cad5faa2de 100644 --- a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsRelease.java +++ b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsRelease.java @@ -16,6 +16,8 @@ package com.android.systemui.flags; +import static com.android.systemui.flags.FlagsCommonModule.ALL_FLAGS; + import static java.util.Objects.requireNonNull; import android.content.res.Resources; @@ -34,6 +36,7 @@ import java.io.PrintWriter; import java.util.Map; import javax.inject.Inject; +import javax.inject.Named; /** * Default implementation of the a Flag manager that returns default values for release builds @@ -49,26 +52,47 @@ public class FeatureFlagsRelease implements FeatureFlags { private final SystemPropertiesHelper mSystemProperties; private final DeviceConfigProxy mDeviceConfigProxy; private final ServerFlagReader mServerFlagReader; + private final Restarter mRestarter; + private final Map<Integer, Flag<?>> mAllFlags; SparseBooleanArray mBooleanCache = new SparseBooleanArray(); SparseArray<String> mStringCache = new SparseArray<>(); + private final ServerFlagReader.ChangeListener mOnPropertiesChanged = + new ServerFlagReader.ChangeListener() { + @Override + public void onChange() { + mRestarter.restart(); + } + }; + @Inject public FeatureFlagsRelease( @Main Resources resources, SystemPropertiesHelper systemProperties, DeviceConfigProxy deviceConfigProxy, - ServerFlagReader serverFlagReader) { + ServerFlagReader serverFlagReader, + @Named(ALL_FLAGS) Map<Integer, Flag<?>> allFlags, + Restarter restarter) { mResources = resources; mSystemProperties = systemProperties; mDeviceConfigProxy = deviceConfigProxy; mServerFlagReader = serverFlagReader; + mAllFlags = allFlags; + mRestarter = restarter; + } + + /** Call after construction to setup listeners. */ + void init() { + mServerFlagReader.listenForChanges(mAllFlags.values(), mOnPropertiesChanged); } @Override - public void addListener(@NonNull Flag<?> flag, @NonNull Listener listener) {} + public void addListener(@NonNull Flag<?> flag, @NonNull Listener listener) { + } @Override - public void removeListener(@NonNull Listener listener) {} + public void removeListener(@NonNull Listener listener) { + } @Override public boolean isEnabled(@NotNull UnreleasedFlag flag) { diff --git a/packages/SystemUI/src/com/android/systemui/flags/FlagCommand.java b/packages/SystemUI/src/com/android/systemui/flags/FlagCommand.java index 4d254313a57b..1e93c0b7002d 100644 --- a/packages/SystemUI/src/com/android/systemui/flags/FlagCommand.java +++ b/packages/SystemUI/src/com/android/systemui/flags/FlagCommand.java @@ -16,6 +16,8 @@ package com.android.systemui.flags; +import static com.android.systemui.flags.FlagsCommonModule.ALL_FLAGS; + import androidx.annotation.NonNull; import com.android.systemui.statusbar.commandline.Command; @@ -42,7 +44,7 @@ public class FlagCommand implements Command { @Inject FlagCommand( FeatureFlagsDebug featureFlags, - @Named(FeatureFlagsDebug.ALL_FLAGS) Map<Integer, Flag<?>> allFlags + @Named(ALL_FLAGS) Map<Integer, Flag<?>> allFlags ) { mFeatureFlags = featureFlags; mAllFlags = allFlags; diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt index 4818bccb1f64..2d511bfabb5e 100644 --- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt +++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021 The Android Open Source Project + * Copyright (C) 2022 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. @@ -124,6 +124,10 @@ object Flags { */ @JvmField val DOZING_MIGRATION_1 = UnreleasedFlag(213, teamfood = true) + @JvmField val NEW_ELLIPSE_DETECTION = UnreleasedFlag(214) + + @JvmField val NEW_UDFPS_OVERLAY = UnreleasedFlag(215) + // 300 - power menu // TODO(b/254512600): Tracking Bug @JvmField val POWER_MENU_LITE = ReleasedFlag(300) @@ -196,7 +200,7 @@ object Flags { // 802 - wallpaper rendering // TODO(b/254512923): Tracking Bug - @JvmField val USE_CANVAS_RENDERER = ReleasedFlag(802) + @JvmField val USE_CANVAS_RENDERER = UnreleasedFlag(802, teamfood = true) // 803 - screen contents translation // TODO(b/254513187): Tracking Bug @@ -230,15 +234,9 @@ object Flags { // 1000 - dock val SIMULATE_DOCK_THROUGH_CHARGING = ReleasedFlag(1000) - // TODO(b/254512444): Tracking Bug - @JvmField val DOCK_SETUP_ENABLED = ReleasedFlag(1001) - // TODO(b/254512758): Tracking Bug @JvmField val ROUNDED_BOX_RIPPLE = ReleasedFlag(1002) - // TODO(b/254512525): Tracking Bug - @JvmField val REFACTORED_DOCK_SETUP = ReleasedFlag(1003, teamfood = true) - // 1100 - windowing @Keep val WM_ENABLE_SHELL_TRANSITIONS = diff --git a/packages/SystemUI/src/com/android/systemui/flags/FlagsCommonModule.kt b/packages/SystemUI/src/com/android/systemui/flags/FlagsCommonModule.kt new file mode 100644 index 000000000000..e1f4944741a0 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/flags/FlagsCommonModule.kt @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2022 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.flags + +import com.android.internal.statusbar.IStatusBarService +import dagger.Module +import dagger.Provides +import javax.inject.Named + +/** Module containing shared code for all FeatureFlag implementations. */ +@Module +interface FlagsCommonModule { + companion object { + const val ALL_FLAGS = "all_flags" + + @JvmStatic + @Provides + @Named(ALL_FLAGS) + fun providesAllFlags(): Map<Int, Flag<*>> { + return Flags.collectFlags() + } + + @JvmStatic + @Provides + fun providesRestarter(barService: IStatusBarService): Restarter { + return object : Restarter { + override fun restart() { + barService.restart() + } + } + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/flags/ServerFlagReader.kt b/packages/SystemUI/src/com/android/systemui/flags/ServerFlagReader.kt index fc5b9f4eea05..694fa01bb4a5 100644 --- a/packages/SystemUI/src/com/android/systemui/flags/ServerFlagReader.kt +++ b/packages/SystemUI/src/com/android/systemui/flags/ServerFlagReader.kt @@ -16,9 +16,13 @@ package com.android.systemui.flags +import android.provider.DeviceConfig +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.util.DeviceConfigProxy -import dagger.Binds import dagger.Module +import dagger.Provides +import java.util.concurrent.Executor import javax.inject.Inject interface ServerFlagReader { @@ -27,40 +31,99 @@ interface ServerFlagReader { /** Returns any stored server-side setting or the default if not set. */ fun readServerOverride(flagId: Int, default: Boolean): Boolean + + /** Register a listener for changes to any of the passed in flags. */ + fun listenForChanges(values: Collection<Flag<*>>, listener: ChangeListener) + + interface ChangeListener { + fun onChange() + } } class ServerFlagReaderImpl @Inject constructor( - private val deviceConfig: DeviceConfigProxy + private val namespace: String, + private val deviceConfig: DeviceConfigProxy, + @Background private val executor: Executor ) : ServerFlagReader { + + private val listeners = + mutableListOf<Pair<ServerFlagReader.ChangeListener, Collection<Flag<*>>>>() + + private val onPropertiesChangedListener = object : DeviceConfig.OnPropertiesChangedListener { + override fun onPropertiesChanged(properties: DeviceConfig.Properties) { + if (properties.namespace != namespace) { + return + } + + for ((listener, flags) in listeners) { + propLoop@ for (propName in properties.keyset) { + for (flag in flags) { + if (propName == getServerOverrideName(flag.id)) { + listener.onChange() + break@propLoop + } + } + } + } + } + } + override fun hasOverride(flagId: Int): Boolean = deviceConfig.getProperty( - SYSUI_NAMESPACE, + namespace, getServerOverrideName(flagId) ) != null override fun readServerOverride(flagId: Int, default: Boolean): Boolean { return deviceConfig.getBoolean( - SYSUI_NAMESPACE, + namespace, getServerOverrideName(flagId), default ) } + override fun listenForChanges( + flags: Collection<Flag<*>>, + listener: ServerFlagReader.ChangeListener + ) { + if (listeners.isEmpty()) { + deviceConfig.addOnPropertiesChangedListener( + namespace, + executor, + onPropertiesChangedListener + ) + } + listeners.add(Pair(listener, flags)) + } + private fun getServerOverrideName(flagId: Int): String { return "flag_override_$flagId" } } -private val SYSUI_NAMESPACE = "systemui" - @Module interface ServerFlagReaderModule { - @Binds - fun bindsReader(impl: ServerFlagReaderImpl): ServerFlagReader + companion object { + private val SYSUI_NAMESPACE = "systemui" + + @JvmStatic + @Provides + @SysUISingleton + fun bindsReader( + deviceConfig: DeviceConfigProxy, + @Background executor: Executor + ): ServerFlagReader { + return ServerFlagReaderImpl( + SYSUI_NAMESPACE, deviceConfig, executor + ) + } + } } class ServerFlagReaderFake : ServerFlagReader { private val flagMap: MutableMap<Int, Boolean> = mutableMapOf() + private val listeners = + mutableListOf<Pair<ServerFlagReader.ChangeListener, Collection<Flag<*>>>>() override fun hasOverride(flagId: Int): Boolean { return flagMap.containsKey(flagId) @@ -72,9 +135,24 @@ class ServerFlagReaderFake : ServerFlagReader { fun setFlagValue(flagId: Int, value: Boolean) { flagMap.put(flagId, value) + + for ((listener, flags) in listeners) { + flagLoop@ for (flag in flags) { + if (flagId == flag.id) { + listener.onChange() + break@flagLoop + } + } + } } fun eraseFlag(flagId: Int) { flagMap.remove(flagId) } + + override fun listenForChanges( + flags: Collection<Flag<*>>, + listener: ServerFlagReader.ChangeListener + ) { + } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfig.kt index d3bb34cd29d4..c600e13cc2dd 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfig.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfig.kt @@ -53,19 +53,19 @@ constructor( override val key: String = BuiltInKeyguardQuickAffordanceKeys.HOME_CONTROLS - override val state: Flow<KeyguardQuickAffordanceConfig.State> = + override val lockScreenState: Flow<KeyguardQuickAffordanceConfig.LockScreenState> = component.canShowWhileLockedSetting.flatMapLatest { canShowWhileLocked -> if (canShowWhileLocked) { stateInternal(component.getControlsListingController().getOrNull()) } else { - flowOf(KeyguardQuickAffordanceConfig.State.Hidden) + flowOf(KeyguardQuickAffordanceConfig.LockScreenState.Hidden) } } - override fun onQuickAffordanceClicked( + override fun onTriggered( expandable: Expandable?, - ): KeyguardQuickAffordanceConfig.OnClickedResult { - return KeyguardQuickAffordanceConfig.OnClickedResult.StartActivity( + ): KeyguardQuickAffordanceConfig.OnTriggeredResult { + return KeyguardQuickAffordanceConfig.OnTriggeredResult.StartActivity( intent = Intent(appContext, ControlsActivity::class.java) .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK) @@ -79,9 +79,9 @@ constructor( private fun stateInternal( listingController: ControlsListingController?, - ): Flow<KeyguardQuickAffordanceConfig.State> { + ): Flow<KeyguardQuickAffordanceConfig.LockScreenState> { if (listingController == null) { - return flowOf(KeyguardQuickAffordanceConfig.State.Hidden) + return flowOf(KeyguardQuickAffordanceConfig.LockScreenState.Hidden) } return conflatedCallbackFlow { @@ -116,7 +116,7 @@ constructor( hasServiceInfos: Boolean, visibility: ControlsComponent.Visibility, @DrawableRes iconResourceId: Int?, - ): KeyguardQuickAffordanceConfig.State { + ): KeyguardQuickAffordanceConfig.LockScreenState { return if ( isFeatureEnabled && hasFavorites && @@ -124,7 +124,7 @@ constructor( iconResourceId != null && visibility == ControlsComponent.Visibility.AVAILABLE ) { - KeyguardQuickAffordanceConfig.State.Visible( + KeyguardQuickAffordanceConfig.LockScreenState.Visible( icon = Icon.Resource( res = iconResourceId, @@ -135,7 +135,7 @@ constructor( ), ) } else { - KeyguardQuickAffordanceConfig.State.Hidden + KeyguardQuickAffordanceConfig.LockScreenState.Hidden } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceConfig.kt index 0dd0ad797411..0a8090bb11ac 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceConfig.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceConfig.kt @@ -20,7 +20,7 @@ package com.android.systemui.keyguard.data.quickaffordance import android.content.Intent import com.android.systemui.animation.Expandable import com.android.systemui.common.shared.model.Icon -import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordanceToggleState +import com.android.systemui.keyguard.shared.quickaffordance.ActivationState import kotlinx.coroutines.flow.Flow /** Defines interface that can act as data source for a single quick affordance model. */ @@ -29,51 +29,54 @@ interface KeyguardQuickAffordanceConfig { /** Unique identifier for this quick affordance. It must be globally unique. */ val key: String - /** The observable [State] of the affordance. */ - val state: Flow<State> + /** + * The ever-changing state of the affordance. + * + * Used to populate the lock screen. + */ + val lockScreenState: Flow<LockScreenState> /** * Notifies that the affordance was clicked by the user. * * @param expandable An [Expandable] to use when animating dialogs or activities - * @return An [OnClickedResult] telling the caller what to do next + * @return An [OnTriggeredResult] telling the caller what to do next */ - fun onQuickAffordanceClicked(expandable: Expandable?): OnClickedResult + fun onTriggered(expandable: Expandable?): OnTriggeredResult /** * Encapsulates the state of a "quick affordance" in the keyguard bottom area (for example, a * button on the lock-screen). */ - sealed class State { + sealed class LockScreenState { /** No affordance should show up. */ - object Hidden : State() + object Hidden : LockScreenState() /** An affordance is visible. */ data class Visible( /** An icon for the affordance. */ val icon: Icon, - /** The toggle state for the affordance. */ - val toggle: KeyguardQuickAffordanceToggleState = - KeyguardQuickAffordanceToggleState.NotSupported, - ) : State() + /** The activation state of the affordance. */ + val activationState: ActivationState = ActivationState.NotSupported, + ) : LockScreenState() } - sealed class OnClickedResult { + sealed class OnTriggeredResult { /** - * Returning this as a result from the [onQuickAffordanceClicked] method means that the - * implementation has taken care of the click, the system will do nothing. + * Returning this as a result from the [onTriggered] method means that the implementation + * has taken care of the action, the system will do nothing. */ - object Handled : OnClickedResult() + object Handled : OnTriggeredResult() /** - * Returning this as a result from the [onQuickAffordanceClicked] method means that the - * implementation has _not_ taken care of the click and the system should start an activity - * using the given [Intent]. + * Returning this as a result from the [onTriggered] method means that the implementation + * has _not_ taken care of the action and the system should start an activity using the + * given [Intent]. */ data class StartActivity( val intent: Intent, val canShowWhileLocked: Boolean, - ) : OnClickedResult() + ) : OnTriggeredResult() } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfig.kt index 9a441392aa07..d620b2a1654c 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfig.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfig.kt @@ -39,46 +39,47 @@ constructor( override val key: String = BuiltInKeyguardQuickAffordanceKeys.QR_CODE_SCANNER - override val state: Flow<KeyguardQuickAffordanceConfig.State> = conflatedCallbackFlow { - val callback = - object : QRCodeScannerController.Callback { - override fun onQRCodeScannerActivityChanged() { - trySendWithFailureLogging(state(), TAG) + override val lockScreenState: Flow<KeyguardQuickAffordanceConfig.LockScreenState> = + conflatedCallbackFlow { + val callback = + object : QRCodeScannerController.Callback { + override fun onQRCodeScannerActivityChanged() { + trySendWithFailureLogging(state(), TAG) + } + override fun onQRCodeScannerPreferenceChanged() { + trySendWithFailureLogging(state(), TAG) + } } - override fun onQRCodeScannerPreferenceChanged() { - trySendWithFailureLogging(state(), TAG) - } - } - - controller.addCallback(callback) - controller.registerQRCodeScannerChangeObservers( - QRCodeScannerController.DEFAULT_QR_CODE_SCANNER_CHANGE, - QRCodeScannerController.QR_CODE_SCANNER_PREFERENCE_CHANGE - ) - // Registering does not push an initial update. - trySendWithFailureLogging(state(), "initial state", TAG) - awaitClose { - controller.unregisterQRCodeScannerChangeObservers( + controller.addCallback(callback) + controller.registerQRCodeScannerChangeObservers( QRCodeScannerController.DEFAULT_QR_CODE_SCANNER_CHANGE, QRCodeScannerController.QR_CODE_SCANNER_PREFERENCE_CHANGE ) - controller.removeCallback(callback) + // Registering does not push an initial update. + trySendWithFailureLogging(state(), "initial state", TAG) + + awaitClose { + controller.unregisterQRCodeScannerChangeObservers( + QRCodeScannerController.DEFAULT_QR_CODE_SCANNER_CHANGE, + QRCodeScannerController.QR_CODE_SCANNER_PREFERENCE_CHANGE + ) + controller.removeCallback(callback) + } } - } - override fun onQuickAffordanceClicked( + override fun onTriggered( expandable: Expandable?, - ): KeyguardQuickAffordanceConfig.OnClickedResult { - return KeyguardQuickAffordanceConfig.OnClickedResult.StartActivity( + ): KeyguardQuickAffordanceConfig.OnTriggeredResult { + return KeyguardQuickAffordanceConfig.OnTriggeredResult.StartActivity( intent = controller.intent, canShowWhileLocked = true, ) } - private fun state(): KeyguardQuickAffordanceConfig.State { + private fun state(): KeyguardQuickAffordanceConfig.LockScreenState { return if (controller.isEnabledForLockScreenButton) { - KeyguardQuickAffordanceConfig.State.Visible( + KeyguardQuickAffordanceConfig.LockScreenState.Visible( icon = Icon.Resource( res = R.drawable.ic_qr_code_scanner, @@ -89,7 +90,7 @@ constructor( ), ) } else { - KeyguardQuickAffordanceConfig.State.Hidden + KeyguardQuickAffordanceConfig.LockScreenState.Hidden } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfig.kt index 8a1267ebadd1..be57a323b5d1 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfig.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfig.kt @@ -46,63 +46,64 @@ constructor( override val key: String = BuiltInKeyguardQuickAffordanceKeys.QUICK_ACCESS_WALLET - override val state: Flow<KeyguardQuickAffordanceConfig.State> = conflatedCallbackFlow { - val callback = - object : QuickAccessWalletClient.OnWalletCardsRetrievedCallback { - override fun onWalletCardsRetrieved(response: GetWalletCardsResponse?) { - trySendWithFailureLogging( - state( - isFeatureEnabled = walletController.isWalletEnabled, - hasCard = response?.walletCards?.isNotEmpty() == true, - tileIcon = walletController.walletClient.tileIcon, - ), - TAG, - ) - } + override val lockScreenState: Flow<KeyguardQuickAffordanceConfig.LockScreenState> = + conflatedCallbackFlow { + val callback = + object : QuickAccessWalletClient.OnWalletCardsRetrievedCallback { + override fun onWalletCardsRetrieved(response: GetWalletCardsResponse?) { + trySendWithFailureLogging( + state( + isFeatureEnabled = walletController.isWalletEnabled, + hasCard = response?.walletCards?.isNotEmpty() == true, + tileIcon = walletController.walletClient.tileIcon, + ), + TAG, + ) + } - override fun onWalletCardRetrievalError(error: GetWalletCardsError?) { - Log.e(TAG, "Wallet card retrieval error, message: \"${error?.message}\"") - trySendWithFailureLogging( - KeyguardQuickAffordanceConfig.State.Hidden, - TAG, - ) + override fun onWalletCardRetrievalError(error: GetWalletCardsError?) { + Log.e(TAG, "Wallet card retrieval error, message: \"${error?.message}\"") + trySendWithFailureLogging( + KeyguardQuickAffordanceConfig.LockScreenState.Hidden, + TAG, + ) + } } - } - - walletController.setupWalletChangeObservers( - callback, - QuickAccessWalletController.WalletChangeEvent.WALLET_PREFERENCE_CHANGE, - QuickAccessWalletController.WalletChangeEvent.DEFAULT_PAYMENT_APP_CHANGE - ) - walletController.updateWalletPreference() - walletController.queryWalletCards(callback) - awaitClose { - walletController.unregisterWalletChangeObservers( + walletController.setupWalletChangeObservers( + callback, QuickAccessWalletController.WalletChangeEvent.WALLET_PREFERENCE_CHANGE, QuickAccessWalletController.WalletChangeEvent.DEFAULT_PAYMENT_APP_CHANGE ) + walletController.updateWalletPreference() + walletController.queryWalletCards(callback) + + awaitClose { + walletController.unregisterWalletChangeObservers( + QuickAccessWalletController.WalletChangeEvent.WALLET_PREFERENCE_CHANGE, + QuickAccessWalletController.WalletChangeEvent.DEFAULT_PAYMENT_APP_CHANGE + ) + } } - } - override fun onQuickAffordanceClicked( + override fun onTriggered( expandable: Expandable?, - ): KeyguardQuickAffordanceConfig.OnClickedResult { + ): KeyguardQuickAffordanceConfig.OnTriggeredResult { walletController.startQuickAccessUiIntent( activityStarter, expandable?.activityLaunchController(), /* hasCard= */ true, ) - return KeyguardQuickAffordanceConfig.OnClickedResult.Handled + return KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled } private fun state( isFeatureEnabled: Boolean, hasCard: Boolean, tileIcon: Drawable?, - ): KeyguardQuickAffordanceConfig.State { + ): KeyguardQuickAffordanceConfig.LockScreenState { return if (isFeatureEnabled && hasCard && tileIcon != null) { - KeyguardQuickAffordanceConfig.State.Visible( + KeyguardQuickAffordanceConfig.LockScreenState.Visible( icon = Icon.Loaded( drawable = tileIcon, @@ -113,7 +114,7 @@ constructor( ), ) } else { - KeyguardQuickAffordanceConfig.State.Hidden + KeyguardQuickAffordanceConfig.LockScreenState.Hidden } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt index 914b9fc52c1a..13d97aaf28da 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt @@ -62,25 +62,25 @@ constructor( } /** - * Notifies that a quick affordance has been clicked by the user. + * Notifies that a quick affordance has been "triggered" (clicked) by the user. * * @param configKey The configuration key corresponding to the [KeyguardQuickAffordanceModel] of * the affordance that was clicked * @param expandable An optional [Expandable] for the activity- or dialog-launch animation */ - fun onQuickAffordanceClicked( + fun onQuickAffordanceTriggered( configKey: String, expandable: Expandable?, ) { @Suppress("UNCHECKED_CAST") val config = registry.get(configKey) - when (val result = config.onQuickAffordanceClicked(expandable)) { - is KeyguardQuickAffordanceConfig.OnClickedResult.StartActivity -> + when (val result = config.onTriggered(expandable)) { + is KeyguardQuickAffordanceConfig.OnTriggeredResult.StartActivity -> launchQuickAffordance( intent = result.intent, canShowWhileLocked = result.canShowWhileLocked, expandable = expandable, ) - is KeyguardQuickAffordanceConfig.OnClickedResult.Handled -> Unit + is KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled -> Unit } } @@ -94,16 +94,20 @@ constructor( // value and avoid subtle bugs where the downstream isn't receiving any values // because one config implementation is not emitting an initial value. For example, // see b/244296596. - config.state.onStart { emit(KeyguardQuickAffordanceConfig.State.Hidden) } + config.lockScreenState.onStart { + emit(KeyguardQuickAffordanceConfig.LockScreenState.Hidden) + } } ) { states -> - val index = states.indexOfFirst { it is KeyguardQuickAffordanceConfig.State.Visible } + val index = + states.indexOfFirst { it is KeyguardQuickAffordanceConfig.LockScreenState.Visible } if (index != -1) { - val visibleState = states[index] as KeyguardQuickAffordanceConfig.State.Visible + val visibleState = + states[index] as KeyguardQuickAffordanceConfig.LockScreenState.Visible KeyguardQuickAffordanceModel.Visible( configKey = configs[index].key, icon = visibleState.icon, - toggle = visibleState.toggle, + activationState = visibleState.activationState, ) } else { KeyguardQuickAffordanceModel.Hidden diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/model/KeyguardQuickAffordanceModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/model/KeyguardQuickAffordanceModel.kt index fc644a9e6067..32560af6af00 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/model/KeyguardQuickAffordanceModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/model/KeyguardQuickAffordanceModel.kt @@ -18,7 +18,7 @@ package com.android.systemui.keyguard.domain.model import com.android.systemui.common.shared.model.Icon -import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordanceToggleState +import com.android.systemui.keyguard.shared.quickaffordance.ActivationState /** * Models a "quick affordance" in the keyguard bottom area (for example, a button on the @@ -34,7 +34,7 @@ sealed class KeyguardQuickAffordanceModel { val configKey: String, /** An icon for the affordance. */ val icon: Icon, - /** The toggle state for the affordance. */ - val toggle: KeyguardQuickAffordanceToggleState, + /** The activation state of the affordance. */ + val activationState: ActivationState, ) : KeyguardQuickAffordanceModel() } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/quickaffordance/KeyguardQuickAffordanceToggleState.kt b/packages/SystemUI/src/com/android/systemui/keyguard/shared/quickaffordance/ActivationState.kt index 55d38a41849d..a68d190a3a0c 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/shared/quickaffordance/KeyguardQuickAffordanceToggleState.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/shared/quickaffordance/ActivationState.kt @@ -17,12 +17,12 @@ package com.android.systemui.keyguard.shared.quickaffordance -/** Enumerates all possible toggle states for a quick affordance on the lock-screen. */ -sealed class KeyguardQuickAffordanceToggleState { - /** Toggling is not supported. */ - object NotSupported : KeyguardQuickAffordanceToggleState() +/** Enumerates all possible activation states for a quick affordance on the lock-screen. */ +sealed class ActivationState { + /** Activation is not supported. */ + object NotSupported : ActivationState() /** The quick affordance is on. */ - object On : KeyguardQuickAffordanceToggleState() + object Active : ActivationState() /** The quick affordance is off. */ - object Off : KeyguardQuickAffordanceToggleState() + object Inactive : ActivationState() } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModel.kt index 6aac9124bab9..b6b230441397 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModel.kt @@ -22,8 +22,8 @@ import com.android.systemui.keyguard.domain.interactor.KeyguardBottomAreaInterac import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardQuickAffordanceInteractor import com.android.systemui.keyguard.domain.model.KeyguardQuickAffordanceModel +import com.android.systemui.keyguard.shared.quickaffordance.ActivationState import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordancePosition -import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordanceToggleState import javax.inject.Inject import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.combine @@ -118,13 +118,13 @@ constructor( animateReveal = animateReveal, icon = icon, onClicked = { parameters -> - quickAffordanceInteractor.onQuickAffordanceClicked( + quickAffordanceInteractor.onQuickAffordanceTriggered( configKey = parameters.configKey, expandable = parameters.expandable, ) }, isClickable = isClickable, - isActivated = toggle is KeyguardQuickAffordanceToggleState.On, + isActivated = activationState is ActivationState.Active, ) is KeyguardQuickAffordanceModel.Hidden -> KeyguardQuickAffordanceViewModel() } diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHierarchyManager.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHierarchyManager.kt index 6b46d8f30cad..cbb670ebf02d 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHierarchyManager.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHierarchyManager.kt @@ -43,7 +43,8 @@ import com.android.systemui.dreams.DreamOverlayStateController import com.android.systemui.keyguard.WakefulnessLifecycle import com.android.systemui.media.dream.MediaDreamComplication import com.android.systemui.plugins.statusbar.StatusBarStateController -import com.android.systemui.shade.NotifPanelEvents +import com.android.systemui.shade.ShadeStateEvents +import com.android.systemui.shade.ShadeStateEvents.ShadeStateEventsListener import com.android.systemui.statusbar.CrossFadeHelper import com.android.systemui.statusbar.StatusBarState import com.android.systemui.statusbar.SysuiStatusBarStateController @@ -96,7 +97,7 @@ constructor( private val dreamOverlayStateController: DreamOverlayStateController, configurationController: ConfigurationController, wakefulnessLifecycle: WakefulnessLifecycle, - panelEventsEvents: NotifPanelEvents, + panelEventsEvents: ShadeStateEvents, private val secureSettings: SecureSettings, @Main private val handler: Handler, ) { @@ -534,8 +535,8 @@ constructor( mediaHosts.forEach { it?.updateViewVisibility() } } - panelEventsEvents.registerListener( - object : NotifPanelEvents.Listener { + panelEventsEvents.addShadeStateEventsListener( + object : ShadeStateEventsListener { override fun onExpandImmediateChanged(isExpandImmediateEnabled: Boolean) { skipQqsOnExpansion = isExpandImmediateEnabled updateDesiredLocation() diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttUtils.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttUtils.kt index 0a6043793ef6..769494a58842 100644 --- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttUtils.kt +++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttUtils.kt @@ -27,10 +27,11 @@ import com.android.systemui.common.shared.model.Icon /** Utility methods for media tap-to-transfer. */ class MediaTttUtils { companion object { - // Used in CTS tests UpdateMediaTapToTransferSenderDisplayTest and - // UpdateMediaTapToTransferReceiverDisplayTest - const val WINDOW_TITLE = "Media Transfer Chip View" - const val WAKE_REASON = "MEDIA_TRANSFER_ACTIVATED" + const val WINDOW_TITLE_SENDER = "Media Transfer Chip View (Sender)" + const val WINDOW_TITLE_RECEIVER = "Media Transfer Chip View (Receiver)" + + const val WAKE_REASON_SENDER = "MEDIA_TRANSFER_ACTIVATED_SENDER" + const val WAKE_REASON_RECEIVER = "MEDIA_TRANSFER_ACTIVATED_RECEIVER" /** * Returns the information needed to display the icon in [Icon] form. diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt index dc794e66b918..7dd9fb4b9cd5 100644 --- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt +++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt @@ -40,7 +40,6 @@ import com.android.systemui.media.taptotransfer.common.MediaTttLogger import com.android.systemui.media.taptotransfer.common.MediaTttUtils import com.android.systemui.statusbar.CommandQueue import com.android.systemui.statusbar.policy.ConfigurationController -import com.android.systemui.temporarydisplay.DEFAULT_TIMEOUT_MILLIS import com.android.systemui.temporarydisplay.TemporaryViewDisplayController import com.android.systemui.temporarydisplay.TemporaryViewInfo import com.android.systemui.util.animation.AnimationUtil.Companion.frames @@ -78,8 +77,6 @@ class MediaTttChipControllerReceiver @Inject constructor( configurationController, powerManager, R.layout.media_ttt_chip_receiver, - MediaTttUtils.WINDOW_TITLE, - MediaTttUtils.WAKE_REASON, ) { @SuppressLint("WrongConstant") // We're allowed to use LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS override val windowLayoutParams = commonWindowLayoutParams.apply { @@ -231,7 +228,7 @@ class MediaTttChipControllerReceiver @Inject constructor( data class ChipReceiverInfo( val routeInfo: MediaRoute2Info, val appIconDrawableOverride: Drawable?, - val appNameOverride: CharSequence? -) : TemporaryViewInfo { - override fun getTimeoutMs() = DEFAULT_TIMEOUT_MILLIS -} + val appNameOverride: CharSequence?, + override val windowTitle: String = MediaTttUtils.WINDOW_TITLE_RECEIVER, + override val wakeReason: String = MediaTttUtils.WAKE_REASON_RECEIVER, +) : TemporaryViewInfo() diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/ChipStateSender.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/ChipStateSender.kt index 6e596ee1f473..af7317c208ab 100644 --- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/ChipStateSender.kt +++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/ChipStateSender.kt @@ -43,7 +43,7 @@ enum class ChipStateSender( @StringRes val stringResId: Int?, val transferStatus: TransferStatus, val endItem: SenderEndItem?, - val timeout: Long = DEFAULT_TIMEOUT_MILLIS + val timeout: Int = DEFAULT_TIMEOUT_MILLIS, ) { /** * A state representing that the two devices are close but not close enough to *start* a cast to @@ -223,6 +223,6 @@ sealed class SenderEndItem { // Give the Transfer*Triggered states a longer timeout since those states represent an active // process and we should keep the user informed about it as long as possible (but don't allow it to // continue indefinitely). -private const val TRANSFER_TRIGGERED_TIMEOUT_MILLIS = 30000L +private const val TRANSFER_TRIGGERED_TIMEOUT_MILLIS = 30000 private const val TAG = "ChipStateSender" diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderCoordinator.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderCoordinator.kt index 1fa8faeecd82..d1ea2d0c83bd 100644 --- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderCoordinator.kt +++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderCoordinator.kt @@ -159,6 +159,9 @@ constructor( } }, vibrationEffect = chipStateSender.transferStatus.vibrationEffect, + windowTitle = MediaTttUtils.WINDOW_TITLE_SENDER, + wakeReason = MediaTttUtils.WAKE_REASON_SENDER, + timeoutMs = chipStateSender.timeout, ) } diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java index b39175e9f9f8..3456c3db15b8 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java @@ -135,7 +135,6 @@ import com.android.systemui.biometrics.AuthController; import com.android.systemui.camera.CameraGestureHelper; import com.android.systemui.classifier.Classifier; import com.android.systemui.classifier.FalsingCollector; -import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.DisplayId; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.doze.DozeLog; @@ -231,7 +230,6 @@ import com.android.systemui.statusbar.window.StatusBarWindowStateController; import com.android.systemui.unfold.SysUIUnfoldComponent; import com.android.systemui.util.Compile; import com.android.systemui.util.LargeScreenUtils; -import com.android.systemui.util.ListenerSet; import com.android.systemui.util.Utils; import com.android.systemui.util.time.SystemClock; import com.android.wm.shell.animation.FlingAnimationUtils; @@ -372,7 +370,6 @@ public final class NotificationPanelViewController { private final TapAgainViewController mTapAgainViewController; private final LargeScreenShadeHeaderController mLargeScreenShadeHeaderController; private final RecordingController mRecordingController; - private final PanelEventsEmitter mPanelEventsEmitter; private final boolean mVibrateOnOpening; private final VelocityTracker mVelocityTracker = VelocityTracker.obtain(); private final FlingAnimationUtils mFlingAnimationUtilsClosing; @@ -880,7 +877,6 @@ public final class NotificationPanelViewController { Provider<KeyguardBottomAreaViewController> keyguardBottomAreaViewControllerProvider, KeyguardUnlockAnimationController keyguardUnlockAnimationController, NotificationListContainer notificationListContainer, - PanelEventsEmitter panelEventsEmitter, NotificationStackSizeCalculator notificationStackSizeCalculator, UnlockedScreenOffAnimationController unlockedScreenOffAnimationController, ShadeTransitionController shadeTransitionController, @@ -993,7 +989,6 @@ public final class NotificationPanelViewController { mMediaDataManager = mediaDataManager; mTapAgainViewController = tapAgainViewController; mSysUiState = sysUiState; - mPanelEventsEmitter = panelEventsEmitter; pulseExpansionHandler.setPulseExpandAbortListener(() -> { if (mQs != null) { mQs.animateHeaderSlidingOut(); @@ -1948,7 +1943,7 @@ public final class NotificationPanelViewController { private void setQsExpandImmediate(boolean expandImmediate) { if (expandImmediate != mQsExpandImmediate) { mQsExpandImmediate = expandImmediate; - mPanelEventsEmitter.notifyExpandImmediateChange(expandImmediate); + mShadeExpansionStateManager.notifyExpandImmediateChange(expandImmediate); } } @@ -3889,7 +3884,7 @@ public final class NotificationPanelViewController { boolean wasRunning = mIsLaunchAnimationRunning; mIsLaunchAnimationRunning = running; if (wasRunning != mIsLaunchAnimationRunning) { - mPanelEventsEmitter.notifyLaunchingActivityChanged(running); + mShadeExpansionStateManager.notifyLaunchingActivityChanged(running); } } @@ -3898,7 +3893,7 @@ public final class NotificationPanelViewController { boolean wasClosing = isClosing(); mClosing = isClosing; if (wasClosing != isClosing) { - mPanelEventsEmitter.notifyPanelCollapsingChanged(isClosing); + mShadeExpansionStateManager.notifyPanelCollapsingChanged(isClosing); } mAmbientState.setIsClosing(isClosing); } @@ -5917,44 +5912,6 @@ public final class NotificationPanelViewController { } } - @SysUISingleton - static class PanelEventsEmitter implements NotifPanelEvents { - - private final ListenerSet<Listener> mListeners = new ListenerSet<>(); - - @Inject - PanelEventsEmitter() { - } - - @Override - public void registerListener(@androidx.annotation.NonNull @NonNull Listener listener) { - mListeners.addIfAbsent(listener); - } - - @Override - public void unregisterListener(@androidx.annotation.NonNull @NonNull Listener listener) { - mListeners.remove(listener); - } - - private void notifyLaunchingActivityChanged(boolean isLaunchingActivity) { - for (Listener cb : mListeners) { - cb.onLaunchingActivityChanged(isLaunchingActivity); - } - } - - private void notifyPanelCollapsingChanged(boolean isCollapsing) { - for (NotifPanelEvents.Listener cb : mListeners) { - cb.onPanelCollapsingChanged(isCollapsing); - } - } - - private void notifyExpandImmediateChange(boolean expandImmediateEnabled) { - for (NotifPanelEvents.Listener cb : mListeners) { - cb.onExpandImmediateChanged(expandImmediateEnabled); - } - } - } - /** Handles MotionEvents for the Shade. */ public final class TouchHandler implements View.OnTouchListener { private long mLastTouchDownTime = -1L; diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotifPanelEventsModule.java b/packages/SystemUI/src/com/android/systemui/shade/ShadeEventsModule.java index 67723843086a..959c339ab3e5 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/NotifPanelEventsModule.java +++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeEventsModule.java @@ -21,10 +21,9 @@ import com.android.systemui.dagger.SysUISingleton; import dagger.Binds; import dagger.Module; -/** Provides a {@link NotifPanelEvents} in {@link SysUISingleton} scope. */ +/** Provides a {@link ShadeStateEvents} in {@link SysUISingleton} scope. */ @Module -public abstract class NotifPanelEventsModule { +public abstract class ShadeEventsModule { @Binds - abstract NotifPanelEvents bindPanelEvents( - NotificationPanelViewController.PanelEventsEmitter impl); + abstract ShadeStateEvents bindShadeEvents(ShadeExpansionStateManager impl); } diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeExpansionStateManager.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeExpansionStateManager.kt index 7bba74a8b125..667392c9796e 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/ShadeExpansionStateManager.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeExpansionStateManager.kt @@ -20,6 +20,7 @@ import android.annotation.IntDef import android.util.Log import androidx.annotation.FloatRange import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.shade.ShadeStateEvents.ShadeStateEventsListener import com.android.systemui.util.Compile import java.util.concurrent.CopyOnWriteArrayList import javax.inject.Inject @@ -30,11 +31,12 @@ import javax.inject.Inject * TODO(b/200063118): Make this class the one source of truth for the state of panel expansion. */ @SysUISingleton -class ShadeExpansionStateManager @Inject constructor() { +class ShadeExpansionStateManager @Inject constructor() : ShadeStateEvents { private val expansionListeners = CopyOnWriteArrayList<ShadeExpansionListener>() private val qsExpansionListeners = CopyOnWriteArrayList<ShadeQsExpansionListener>() private val stateListeners = CopyOnWriteArrayList<ShadeStateListener>() + private val shadeStateEventsListeners = CopyOnWriteArrayList<ShadeStateEventsListener>() @PanelState private var state: Int = STATE_CLOSED @FloatRange(from = 0.0, to = 1.0) private var fraction: Float = 0f @@ -79,6 +81,14 @@ class ShadeExpansionStateManager @Inject constructor() { stateListeners.remove(listener) } + override fun addShadeStateEventsListener(listener: ShadeStateEventsListener) { + shadeStateEventsListeners.addIfAbsent(listener) + } + + override fun removeShadeStateEventsListener(listener: ShadeStateEventsListener) { + shadeStateEventsListeners.remove(listener) + } + /** Returns true if the panel is currently closed and false otherwise. */ fun isClosed(): Boolean = state == STATE_CLOSED @@ -162,6 +172,24 @@ class ShadeExpansionStateManager @Inject constructor() { stateListeners.forEach { it.onPanelStateChanged(state) } } + fun notifyLaunchingActivityChanged(isLaunchingActivity: Boolean) { + for (cb in shadeStateEventsListeners) { + cb.onLaunchingActivityChanged(isLaunchingActivity) + } + } + + fun notifyPanelCollapsingChanged(isCollapsing: Boolean) { + for (cb in shadeStateEventsListeners) { + cb.onPanelCollapsingChanged(isCollapsing) + } + } + + fun notifyExpandImmediateChange(expandImmediateEnabled: Boolean) { + for (cb in shadeStateEventsListeners) { + cb.onExpandImmediateChanged(expandImmediateEnabled) + } + } + private fun debugLog(msg: String) { if (!DEBUG) return Log.v(TAG, msg) diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotifPanelEvents.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeStateEvents.kt index 4558061de1a2..56bb1a6020cf 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/NotifPanelEvents.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeStateEvents.kt @@ -16,27 +16,25 @@ package com.android.systemui.shade -/** Provides certain notification panel events. */ -interface NotifPanelEvents { +/** Provides certain notification panel events. */ +interface ShadeStateEvents { - /** Registers callbacks to be invoked when notification panel events occur. */ - fun registerListener(listener: Listener) + /** Registers callbacks to be invoked when notification panel events occur. */ + fun addShadeStateEventsListener(listener: ShadeStateEventsListener) - /** Unregisters callbacks previously registered via [registerListener] */ - fun unregisterListener(listener: Listener) + /** Unregisters callbacks previously registered via [addShadeStateEventsListener] */ + fun removeShadeStateEventsListener(listener: ShadeStateEventsListener) /** Callbacks for certain notification panel events. */ - interface Listener { + interface ShadeStateEventsListener { /** Invoked when the notification panel starts or stops collapsing. */ - @JvmDefault - fun onPanelCollapsingChanged(isCollapsing: Boolean) {} + @JvmDefault fun onPanelCollapsingChanged(isCollapsing: Boolean) {} /** * Invoked when the notification panel starts or stops launching an [android.app.Activity]. */ - @JvmDefault - fun onLaunchingActivityChanged(isLaunchingActivity: Boolean) {} + @JvmDefault fun onLaunchingActivityChanged(isLaunchingActivity: Boolean) {} /** * Invoked when the "expand immediate" attribute changes. @@ -47,7 +45,6 @@ interface NotifPanelEvents { * Another example is when full QS is showing, and we swipe up from the bottom. Instead of * going to QQS, the panel fully collapses. */ - @JvmDefault - fun onExpandImmediateChanged(isExpandImmediateEnabled: Boolean) {} + @JvmDefault fun onExpandImmediateChanged(isExpandImmediateEnabled: Boolean) {} } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinator.java index d3bc257d8a54..3002a6820990 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinator.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinator.java @@ -28,7 +28,7 @@ import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dump.DumpManager; import com.android.systemui.keyguard.WakefulnessLifecycle; import com.android.systemui.plugins.statusbar.StatusBarStateController; -import com.android.systemui.shade.NotifPanelEvents; +import com.android.systemui.shade.ShadeStateEvents; import com.android.systemui.statusbar.notification.collection.GroupEntry; import com.android.systemui.statusbar.notification.collection.ListEntry; import com.android.systemui.statusbar.notification.collection.NotifPipeline; @@ -55,12 +55,12 @@ import javax.inject.Inject; // TODO(b/204468557): Move to @CoordinatorScope @SysUISingleton public class VisualStabilityCoordinator implements Coordinator, Dumpable, - NotifPanelEvents.Listener { + ShadeStateEvents.ShadeStateEventsListener { public static final String TAG = "VisualStability"; public static final boolean DEBUG = Compile.IS_DEBUG && Log.isLoggable(TAG, Log.VERBOSE); private final DelayableExecutor mDelayableExecutor; private final HeadsUpManager mHeadsUpManager; - private final NotifPanelEvents mNotifPanelEvents; + private final ShadeStateEvents mShadeStateEvents; private final StatusBarStateController mStatusBarStateController; private final VisualStabilityProvider mVisualStabilityProvider; private final WakefulnessLifecycle mWakefulnessLifecycle; @@ -92,7 +92,7 @@ public class VisualStabilityCoordinator implements Coordinator, Dumpable, DelayableExecutor delayableExecutor, DumpManager dumpManager, HeadsUpManager headsUpManager, - NotifPanelEvents notifPanelEvents, + ShadeStateEvents shadeStateEvents, StatusBarStateController statusBarStateController, VisualStabilityProvider visualStabilityProvider, WakefulnessLifecycle wakefulnessLifecycle) { @@ -101,7 +101,7 @@ public class VisualStabilityCoordinator implements Coordinator, Dumpable, mWakefulnessLifecycle = wakefulnessLifecycle; mStatusBarStateController = statusBarStateController; mDelayableExecutor = delayableExecutor; - mNotifPanelEvents = notifPanelEvents; + mShadeStateEvents = shadeStateEvents; dumpManager.registerDumpable(this); } @@ -114,7 +114,7 @@ public class VisualStabilityCoordinator implements Coordinator, Dumpable, mStatusBarStateController.addCallback(mStatusBarStateControllerListener); mPulsing = mStatusBarStateController.isPulsing(); - mNotifPanelEvents.registerListener(this); + mShadeStateEvents.addShadeStateEventsListener(this); pipeline.setVisualStabilityManager(mNotifStabilityManager); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java index da4cceda531f..ff6389141575 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java @@ -32,8 +32,8 @@ import com.android.systemui.dagger.qualifiers.UiBackground; import com.android.systemui.people.widget.PeopleSpaceWidgetManager; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.settings.UserContextProvider; -import com.android.systemui.shade.NotifPanelEventsModule; import com.android.systemui.shade.ShadeController; +import com.android.systemui.shade.ShadeEventsModule; import com.android.systemui.statusbar.NotificationListener; import com.android.systemui.statusbar.notification.AssistantFeedbackController; import com.android.systemui.statusbar.notification.collection.NotifInflaterImpl; @@ -93,7 +93,7 @@ import dagger.Provides; @Module(includes = { CoordinatorsModule.class, KeyguardNotificationVisibilityProviderModule.class, - NotifPanelEventsModule.class, + ShadeEventsModule.class, NotifPipelineChoreographerModule.class, NotificationSectionHeadersModule.class, }) diff --git a/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayController.kt b/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayController.kt index f0a50de02b3a..637fac05f0b6 100644 --- a/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayController.kt +++ b/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayController.kt @@ -44,11 +44,6 @@ import com.android.systemui.util.concurrency.DelayableExecutor * * The generic type T is expected to contain all the information necessary for the subclasses to * display the view in a certain state, since they receive <T> in [updateView]. - * - * @property windowTitle the title to use for the window that displays the temporary view. Should be - * normally cased, like "Window Title". - * @property wakeReason a string used for logging if we needed to wake the screen in order to - * display the temporary view. Should be screaming snake cased, like WAKE_REASON. */ abstract class TemporaryViewDisplayController<T : TemporaryViewInfo, U : TemporaryViewLogger>( internal val context: Context, @@ -59,8 +54,6 @@ abstract class TemporaryViewDisplayController<T : TemporaryViewInfo, U : Tempora private val configurationController: ConfigurationController, private val powerManager: PowerManager, @LayoutRes private val viewLayoutRes: Int, - private val windowTitle: String, - private val wakeReason: String, ) : CoreStartable { /** * Window layout params that will be used as a starting point for the [windowLayoutParams] of @@ -72,7 +65,6 @@ abstract class TemporaryViewDisplayController<T : TemporaryViewInfo, U : Tempora type = WindowManager.LayoutParams.TYPE_SYSTEM_ERROR flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL - title = windowTitle format = PixelFormat.TRANSLUCENT setTrustedOverlay() } @@ -100,29 +92,40 @@ abstract class TemporaryViewDisplayController<T : TemporaryViewInfo, U : Tempora fun displayView(newInfo: T) { val currentDisplayInfo = displayInfo - if (currentDisplayInfo != null) { + if (currentDisplayInfo != null && + currentDisplayInfo.info.windowTitle == newInfo.windowTitle) { + // We're already displaying information in the correctly-titled window, so we just need + // to update the view. currentDisplayInfo.info = newInfo updateView(currentDisplayInfo.info, currentDisplayInfo.view) } else { - // The view is new, so set up all our callbacks and inflate the view + if (currentDisplayInfo != null) { + // We're already displaying information but that information is under a different + // window title. So, we need to remove the old window with the old title and add a + // new window with the new title. + removeView(removalReason = "New info has new window title: ${newInfo.windowTitle}") + } + + // At this point, we're guaranteed to no longer be displaying a view. + // So, set up all our callbacks and inflate the view. configurationController.addCallback(displayScaleListener) // Wake the screen if necessary so the user will see the view. (Per b/239426653, we want // the view to show over the dream state, so we should only wake up if the screen is // completely off.) if (!powerManager.isScreenOn) { powerManager.wakeUp( - SystemClock.uptimeMillis(), - PowerManager.WAKE_REASON_APPLICATION, - "com.android.systemui:$wakeReason", + SystemClock.uptimeMillis(), + PowerManager.WAKE_REASON_APPLICATION, + "com.android.systemui:${newInfo.wakeReason}", ) } - logger.logChipAddition() + logger.logViewAddition(newInfo.windowTitle) inflateAndUpdateView(newInfo) } // Cancel and re-set the view timeout each time we get a new state. val timeout = accessibilityManager.getRecommendedTimeoutMillis( - newInfo.getTimeoutMs().toInt(), + newInfo.timeoutMs, // Not all views have controls so FLAG_CONTENT_CONTROLS might be superfluous, but // include it just to be safe. FLAG_CONTENT_ICONS or FLAG_CONTENT_TEXT or FLAG_CONTENT_CONTROLS @@ -147,7 +150,12 @@ abstract class TemporaryViewDisplayController<T : TemporaryViewInfo, U : Tempora val newDisplayInfo = DisplayInfo(newView, newInfo) displayInfo = newDisplayInfo updateView(newDisplayInfo.info, newDisplayInfo.view) - windowManager.addView(newView, windowLayoutParams) + + val paramsWithTitle = WindowManager.LayoutParams().also { + it.copyFrom(windowLayoutParams) + it.title = newInfo.windowTitle + } + windowManager.addView(newView, paramsWithTitle) animateViewIn(newView) } @@ -177,7 +185,7 @@ abstract class TemporaryViewDisplayController<T : TemporaryViewInfo, U : Tempora val currentView = currentDisplayInfo.view animateViewOut(currentView) { windowManager.removeView(currentView) } - logger.logChipRemoval(removalReason) + logger.logViewRemoval(removalReason) configurationController.removeCallback(displayScaleListener) // Re-set to null immediately (instead as part of the animation end runnable) so // that if a new view event comes in while this view is animating out, we still display the diff --git a/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewInfo.kt b/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewInfo.kt index 4fe753a80faf..cbb500296888 100644 --- a/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewInfo.kt +++ b/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewInfo.kt @@ -19,12 +19,24 @@ package com.android.systemui.temporarydisplay /** * A superclass view state used with [TemporaryViewDisplayController]. */ -interface TemporaryViewInfo { +abstract class TemporaryViewInfo { /** - * Returns the amount of time the given view state should display on the screen before it times - * out and disappears. + * The title to use for the window that displays the temporary view. Should be normally cased, + * like "Window Title". */ - fun getTimeoutMs(): Long = DEFAULT_TIMEOUT_MILLIS + abstract val windowTitle: String + + /** + * A string used for logging if we needed to wake the screen in order to display the temporary + * view. Should be screaming snake cased, like WAKE_REASON. + */ + abstract val wakeReason: String + + /** + * The amount of time the given view state should display on the screen before it times out and + * disappears. + */ + open val timeoutMs: Int = DEFAULT_TIMEOUT_MILLIS } -const val DEFAULT_TIMEOUT_MILLIS = 10000L +const val DEFAULT_TIMEOUT_MILLIS = 10000 diff --git a/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewLogger.kt b/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewLogger.kt index a7185cb18c40..428a104484a7 100644 --- a/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewLogger.kt @@ -24,13 +24,13 @@ open class TemporaryViewLogger( internal val buffer: LogBuffer, internal val tag: String, ) { - /** Logs that we added the chip to a new window. */ - fun logChipAddition() { - buffer.log(tag, LogLevel.DEBUG, {}, { "Chip added" }) + /** Logs that we added the view in a window titled [windowTitle]. */ + fun logViewAddition(windowTitle: String) { + buffer.log(tag, LogLevel.DEBUG, { str1 = windowTitle }, { "View added. window=$str1" }) } /** Logs that we removed the chip for the given [reason]. */ - fun logChipRemoval(reason: String) { - buffer.log(tag, LogLevel.DEBUG, { str1 = reason }, { "Chip removed due to $str1" }) + fun logViewRemoval(reason: String) { + buffer.log(tag, LogLevel.DEBUG, { str1 = reason }, { "View removed due to: $str1" }) } } diff --git a/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinator.kt b/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinator.kt index b8930a45cd33..87b6e8d3af34 100644 --- a/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinator.kt +++ b/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinator.kt @@ -38,9 +38,6 @@ import com.android.systemui.common.ui.binder.IconViewBinder import com.android.systemui.common.ui.binder.TextViewBinder import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Main -import com.android.systemui.media.taptotransfer.common.MediaTttLogger -import com.android.systemui.media.taptotransfer.common.MediaTttUtils -import com.android.systemui.media.taptotransfer.sender.MediaTttSenderLogger import com.android.systemui.plugins.FalsingManager import com.android.systemui.statusbar.VibratorHelper import com.android.systemui.statusbar.policy.ConfigurationController @@ -64,14 +61,11 @@ import javax.inject.Inject * Only one chipbar may be shown at a time. * TODO(b/245610654): Should we just display whichever chipbar was most recently requested, or do we * need to maintain a priority ordering? - * - * TODO(b/245610654): Remove all media-related items from this class so it's just for generic - * chipbars. */ @SysUISingleton open class ChipbarCoordinator @Inject constructor( context: Context, - @MediaTttSenderLogger logger: MediaTttLogger, + logger: ChipbarLogger, windowManager: WindowManager, @Main mainExecutor: DelayableExecutor, accessibilityManager: AccessibilityManager, @@ -81,7 +75,7 @@ open class ChipbarCoordinator @Inject constructor( private val falsingCollector: FalsingCollector, private val viewUtil: ViewUtil, private val vibratorHelper: VibratorHelper, -) : TemporaryViewDisplayController<ChipbarInfo, MediaTttLogger>( +) : TemporaryViewDisplayController<ChipbarInfo, ChipbarLogger>( context, logger, windowManager, @@ -90,8 +84,6 @@ open class ChipbarCoordinator @Inject constructor( configurationController, powerManager, R.layout.chipbar, - MediaTttUtils.WINDOW_TITLE, - MediaTttUtils.WAKE_REASON, ) { private lateinit var parent: ChipbarRootView @@ -106,7 +98,16 @@ open class ChipbarCoordinator @Inject constructor( newInfo: ChipbarInfo, currentView: ViewGroup ) { - // TODO(b/245610654): Adding logging here. + logger.logViewUpdate( + newInfo.windowTitle, + newInfo.text.loadText(context), + when (newInfo.endItem) { + null -> "null" + is ChipbarEndItem.Loading -> "loading" + is ChipbarEndItem.Error -> "error" + is ChipbarEndItem.Button -> "button(${newInfo.endItem.text.loadText(context)})" + } + ) // Detect falsing touches on the chip. parent = currentView.requireViewById(R.id.chipbar_root_view) diff --git a/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarInfo.kt b/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarInfo.kt index 57fde87114d0..6237365d0cee 100644 --- a/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarInfo.kt +++ b/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarInfo.kt @@ -37,7 +37,10 @@ data class ChipbarInfo( val text: Text, val endItem: ChipbarEndItem?, val vibrationEffect: VibrationEffect? = null, -) : TemporaryViewInfo + override val windowTitle: String, + override val wakeReason: String, + override val timeoutMs: Int, +) : TemporaryViewInfo() /** The possible items to display at the end of the chipbar. */ sealed class ChipbarEndItem { diff --git a/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarLogger.kt b/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarLogger.kt new file mode 100644 index 000000000000..e477cd68673a --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarLogger.kt @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2022 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.temporarydisplay.chipbar + +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.plugins.log.LogBuffer +import com.android.systemui.plugins.log.LogLevel +import com.android.systemui.temporarydisplay.TemporaryViewLogger +import com.android.systemui.temporarydisplay.dagger.ChipbarLog +import javax.inject.Inject + +/** A logger for the chipbar. */ +@SysUISingleton +class ChipbarLogger +@Inject +constructor( + @ChipbarLog buffer: LogBuffer, +) : TemporaryViewLogger(buffer, "ChipbarLog") { + /** + * Logs that the chipbar was updated to display in a window named [windowTitle], with [text] and + * [endItemDesc]. + */ + fun logViewUpdate(windowTitle: String, text: String?, endItemDesc: String) { + buffer.log( + tag, + LogLevel.DEBUG, + { + str1 = windowTitle + str2 = text + str3 = endItemDesc + }, + { "Chipbar updated. window=$str1 text=$str2 endItem=$str3" } + ) + } +} diff --git a/packages/SystemUI/src/com/android/systemui/temporarydisplay/dagger/ChipbarLog.kt b/packages/SystemUI/src/com/android/systemui/temporarydisplay/dagger/ChipbarLog.kt new file mode 100644 index 000000000000..5f101f2f388d --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/temporarydisplay/dagger/ChipbarLog.kt @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2022 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.temporarydisplay.dagger + +import javax.inject.Qualifier + +/** Status bar connectivity logs in table format. */ +@Qualifier +@MustBeDocumented +@kotlin.annotation.Retention(AnnotationRetention.RUNTIME) +annotation class ChipbarLog diff --git a/packages/SystemUI/src/com/android/systemui/temporarydisplay/dagger/TemporaryDisplayModule.kt b/packages/SystemUI/src/com/android/systemui/temporarydisplay/dagger/TemporaryDisplayModule.kt new file mode 100644 index 000000000000..cf0a1835c8e8 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/temporarydisplay/dagger/TemporaryDisplayModule.kt @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2022 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.temporarydisplay.dagger + +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.log.LogBufferFactory +import com.android.systemui.plugins.log.LogBuffer +import dagger.Module +import dagger.Provides + +@Module +interface TemporaryDisplayModule { + @Module + companion object { + @JvmStatic + @Provides + @SysUISingleton + @ChipbarLog + fun provideChipbarLogBuffer(factory: LogBufferFactory): LogBuffer { + return factory.create("ChipbarLog", 40) + } + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java index 49c6fd14997e..ed957db2852b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java @@ -69,6 +69,7 @@ import com.android.systemui.R; import com.android.systemui.SysuiTestCase; import com.android.systemui.animation.ActivityLaunchAnimator; import com.android.systemui.dump.DumpManager; +import com.android.systemui.flags.FeatureFlags; import com.android.systemui.keyguard.ScreenLifecycle; import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.statusbar.StatusBarStateController; @@ -169,6 +170,8 @@ public class UdfpsControllerTest extends SysuiTestCase { private FakeExecutor mFgExecutor; @Mock private UdfpsDisplayMode mUdfpsDisplayMode; + @Mock + private FeatureFlags mFeatureFlags; // Stuff for configuring mocks @Mock @@ -250,6 +253,7 @@ public class UdfpsControllerTest extends SysuiTestCase { mStatusBarKeyguardViewManager, mDumpManager, mKeyguardUpdateMonitor, + mFeatureFlags, mFalsingManager, mPowerManager, mAccessibilityManager, diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/model/BiometricPromptRequestTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/model/BiometricPromptRequestTest.kt index 2eeff9fcdd8a..4c5e3c1bc6a6 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/model/BiometricPromptRequestTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/model/BiometricPromptRequestTest.kt @@ -1,6 +1,7 @@ package com.android.systemui.biometrics.domain.model import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase import com.android.systemui.biometrics.promptInfo import com.google.common.truth.Truth.assertThat import org.junit.Test @@ -12,7 +13,7 @@ private const val OPERATION_ID = 8L @SmallTest @RunWith(JUnit4::class) -class BiometricPromptRequestTest { +class BiometricPromptRequestTest : SysuiTestCase() { @Test fun biometricRequestFromPromptInfo() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsDebugTest.kt b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsDebugTest.kt index 20a82c63cfdd..4b3b70e3ae77 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsDebugTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsDebugTest.kt @@ -88,6 +88,7 @@ class FeatureFlagsDebugTest : SysuiTestCase() { flagMap, restarter ) + mFeatureFlagsDebug.init() verify(flagManager).onSettingsChangedAction = any() broadcastReceiver = withArgCaptor { verify(mockContext).registerReceiver(capture(), any(), nullable(), nullable(), @@ -255,11 +256,11 @@ class FeatureFlagsDebugTest : SysuiTestCase() { broadcastReceiver.onReceive(mockContext, Intent()) broadcastReceiver.onReceive(mockContext, Intent("invalid action")) broadcastReceiver.onReceive(mockContext, Intent(FlagManager.ACTION_SET_FLAG)) - setByBroadcast(0, false) // unknown id does nothing - setByBroadcast(1, "string") // wrong type does nothing - setByBroadcast(2, 123) // wrong type does nothing - setByBroadcast(3, false) // wrong type does nothing - setByBroadcast(4, 123) // wrong type does nothing + setByBroadcast(0, false) // unknown id does nothing + setByBroadcast(1, "string") // wrong type does nothing + setByBroadcast(2, 123) // wrong type does nothing + setByBroadcast(3, false) // wrong type does nothing + setByBroadcast(4, 123) // wrong type does nothing verifyNoMoreInteractions(flagManager, secureSettings) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsReleaseTest.kt b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsReleaseTest.kt index 575c14262b74..b2dd60c9566d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsReleaseTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsReleaseTest.kt @@ -38,8 +38,9 @@ class FeatureFlagsReleaseTest : SysuiTestCase() { @Mock private lateinit var mResources: Resources @Mock private lateinit var mSystemProperties: SystemPropertiesHelper + @Mock private lateinit var restarter: Restarter + private val flagMap = mutableMapOf<Int, Flag<*>>() private val serverFlagReader = ServerFlagReaderFake() - private val deviceConfig = DeviceConfigProxyFake() @Before @@ -49,7 +50,9 @@ class FeatureFlagsReleaseTest : SysuiTestCase() { mResources, mSystemProperties, deviceConfig, - serverFlagReader) + serverFlagReader, + flagMap, + restarter) } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/ServerFlagReaderImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/flags/ServerFlagReaderImplTest.kt new file mode 100644 index 000000000000..6f5f460d41c4 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/flags/ServerFlagReaderImplTest.kt @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2022 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.flags + +import android.test.suitebuilder.annotation.SmallTest +import android.testing.AndroidTestingRunner +import com.android.systemui.SysuiTestCase +import com.android.systemui.util.DeviceConfigProxyFake +import com.android.systemui.util.concurrency.FakeExecutor +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.Mockito.verify +import org.mockito.MockitoAnnotations + +@SmallTest +@RunWith(AndroidTestingRunner::class) +class ServerFlagReaderImplTest : SysuiTestCase() { + + private val NAMESPACE = "test" + + @Mock private lateinit var changeListener: ServerFlagReader.ChangeListener + + private lateinit var serverFlagReader: ServerFlagReaderImpl + private val deviceConfig = DeviceConfigProxyFake() + private val executor = FakeExecutor(FakeSystemClock()) + + @Before + fun setup() { + MockitoAnnotations.initMocks(this) + + serverFlagReader = ServerFlagReaderImpl(NAMESPACE, deviceConfig, executor) + } + + @Test + fun testChange_alertsListener() { + val flag = ReleasedFlag(1) + serverFlagReader.listenForChanges(listOf(flag), changeListener) + + deviceConfig.setProperty(NAMESPACE, "flag_override_1", "1", false) + executor.runAllReady() + + verify(changeListener).onChange() + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/FakeKeyguardQuickAffordanceConfig.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/FakeKeyguardQuickAffordanceConfig.kt index ce110084dbc4..f18acbad14f2 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/FakeKeyguardQuickAffordanceConfig.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/FakeKeyguardQuickAffordanceConfig.kt @@ -18,7 +18,7 @@ package com.android.systemui.keyguard.data.quickaffordance import com.android.systemui.animation.Expandable -import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig.OnClickedResult +import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig.OnTriggeredResult import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.yield @@ -33,22 +33,23 @@ abstract class FakeKeyguardQuickAffordanceConfig( override val key: String, ) : KeyguardQuickAffordanceConfig { - var onClickedResult: OnClickedResult = OnClickedResult.Handled + var onTriggeredResult: OnTriggeredResult = OnTriggeredResult.Handled - private val _state = - MutableStateFlow<KeyguardQuickAffordanceConfig.State>( - KeyguardQuickAffordanceConfig.State.Hidden + private val _lockScreenState = + MutableStateFlow<KeyguardQuickAffordanceConfig.LockScreenState>( + KeyguardQuickAffordanceConfig.LockScreenState.Hidden ) - override val state: Flow<KeyguardQuickAffordanceConfig.State> = _state + override val lockScreenState: Flow<KeyguardQuickAffordanceConfig.LockScreenState> = + _lockScreenState - override fun onQuickAffordanceClicked( + override fun onTriggered( expandable: Expandable?, - ): OnClickedResult { - return onClickedResult + ): OnTriggeredResult { + return onTriggeredResult } - suspend fun setState(state: KeyguardQuickAffordanceConfig.State) { - _state.value = state + suspend fun setState(lockScreenState: KeyguardQuickAffordanceConfig.LockScreenState) { + _lockScreenState.value = lockScreenState // Yield to allow the test's collection coroutine to "catch up" and collect this value // before the test continues to the next line. // TODO(b/239834928): once coroutines.test is updated, switch to the approach described in diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigParameterizedStateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigParameterizedStateTest.kt index b120303d4c04..c94cec6e313a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigParameterizedStateTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigParameterizedStateTest.kt @@ -122,8 +122,8 @@ class HomeControlsKeyguardQuickAffordanceConfigParameterizedStateTest : SysuiTes emptyList() } ) - val values = mutableListOf<KeyguardQuickAffordanceConfig.State>() - val job = underTest.state.onEach(values::add).launchIn(this) + val values = mutableListOf<KeyguardQuickAffordanceConfig.LockScreenState>() + val job = underTest.lockScreenState.onEach(values::add).launchIn(this) if (canShowWhileLocked) { verify(controlsListingController).addCallback(callbackCaptor.capture()) @@ -139,9 +139,9 @@ class HomeControlsKeyguardQuickAffordanceConfigParameterizedStateTest : SysuiTes assertThat(values.last()) .isInstanceOf( if (isVisibleExpected) { - KeyguardQuickAffordanceConfig.State.Visible::class.java + KeyguardQuickAffordanceConfig.LockScreenState.Visible::class.java } else { - KeyguardQuickAffordanceConfig.State.Hidden::class.java + KeyguardQuickAffordanceConfig.LockScreenState.Hidden::class.java } ) job.cancel() diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigTest.kt index ce8d36d5012a..659c1e573ca3 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigTest.kt @@ -23,7 +23,7 @@ import com.android.systemui.SysuiTestCase import com.android.systemui.animation.Expandable import com.android.systemui.controls.controller.ControlsController import com.android.systemui.controls.dagger.ControlsComponent -import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig.OnClickedResult +import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig.OnTriggeredResult import com.android.systemui.util.mockito.mock import com.google.common.truth.Truth.assertThat import java.util.Optional @@ -72,11 +72,11 @@ class HomeControlsKeyguardQuickAffordanceConfigTest : SysuiTestCase() { whenever(component.getVisibility()).thenReturn(ControlsComponent.Visibility.AVAILABLE) whenever(controlsController.getFavorites()).thenReturn(listOf(mock())) - val values = mutableListOf<KeyguardQuickAffordanceConfig.State>() - val job = underTest.state.onEach(values::add).launchIn(this) + val values = mutableListOf<KeyguardQuickAffordanceConfig.LockScreenState>() + val job = underTest.lockScreenState.onEach(values::add).launchIn(this) assertThat(values.last()) - .isInstanceOf(KeyguardQuickAffordanceConfig.State.Hidden::class.java) + .isInstanceOf(KeyguardQuickAffordanceConfig.LockScreenState.Hidden::class.java) job.cancel() } @@ -91,31 +91,32 @@ class HomeControlsKeyguardQuickAffordanceConfigTest : SysuiTestCase() { whenever(component.getVisibility()).thenReturn(ControlsComponent.Visibility.AVAILABLE) whenever(controlsController.getFavorites()).thenReturn(listOf(mock())) - val values = mutableListOf<KeyguardQuickAffordanceConfig.State>() - val job = underTest.state.onEach(values::add).launchIn(this) + val values = mutableListOf<KeyguardQuickAffordanceConfig.LockScreenState>() + val job = underTest.lockScreenState.onEach(values::add).launchIn(this) assertThat(values.last()) - .isInstanceOf(KeyguardQuickAffordanceConfig.State.Hidden::class.java) + .isInstanceOf(KeyguardQuickAffordanceConfig.LockScreenState.Hidden::class.java) job.cancel() } @Test - fun `onQuickAffordanceClicked - canShowWhileLockedSetting is true`() = runBlockingTest { + fun `onQuickAffordanceTriggered - canShowWhileLockedSetting is true`() = runBlockingTest { whenever(component.canShowWhileLockedSetting).thenReturn(MutableStateFlow(true)) - val onClickedResult = underTest.onQuickAffordanceClicked(expandable) + val onClickedResult = underTest.onTriggered(expandable) - assertThat(onClickedResult).isInstanceOf(OnClickedResult.StartActivity::class.java) - assertThat((onClickedResult as OnClickedResult.StartActivity).canShowWhileLocked).isTrue() + assertThat(onClickedResult).isInstanceOf(OnTriggeredResult.StartActivity::class.java) + assertThat((onClickedResult as OnTriggeredResult.StartActivity).canShowWhileLocked).isTrue() } @Test - fun `onQuickAffordanceClicked - canShowWhileLockedSetting is false`() = runBlockingTest { + fun `onQuickAffordanceTriggered - canShowWhileLockedSetting is false`() = runBlockingTest { whenever(component.canShowWhileLockedSetting).thenReturn(MutableStateFlow(false)) - val onClickedResult = underTest.onQuickAffordanceClicked(expandable) + val onClickedResult = underTest.onTriggered(expandable) - assertThat(onClickedResult).isInstanceOf(OnClickedResult.StartActivity::class.java) - assertThat((onClickedResult as OnClickedResult.StartActivity).canShowWhileLocked).isFalse() + assertThat(onClickedResult).isInstanceOf(OnTriggeredResult.StartActivity::class.java) + assertThat((onClickedResult as OnTriggeredResult.StartActivity).canShowWhileLocked) + .isFalse() } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfigTest.kt index 93464400d1ab..61a3f9f07600 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfigTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfigTest.kt @@ -20,7 +20,7 @@ package com.android.systemui.keyguard.data.quickaffordance import android.content.Intent import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase -import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig.OnClickedResult +import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig.OnTriggeredResult import com.android.systemui.qrcodescanner.controller.QRCodeScannerController import com.android.systemui.util.mockito.argumentCaptor import com.android.systemui.util.mockito.mock @@ -56,9 +56,9 @@ class QrCodeScannerKeyguardQuickAffordanceConfigTest : SysuiTestCase() { @Test fun `affordance - sets up registration and delivers initial model`() = runBlockingTest { whenever(controller.isEnabledForLockScreenButton).thenReturn(true) - var latest: KeyguardQuickAffordanceConfig.State? = null + var latest: KeyguardQuickAffordanceConfig.LockScreenState? = null - val job = underTest.state.onEach { latest = it }.launchIn(this) + val job = underTest.lockScreenState.onEach { latest = it }.launchIn(this) val callbackCaptor = argumentCaptor<QRCodeScannerController.Callback>() verify(controller).addCallback(callbackCaptor.capture()) @@ -77,8 +77,8 @@ class QrCodeScannerKeyguardQuickAffordanceConfigTest : SysuiTestCase() { fun `affordance - scanner activity changed - delivers model with updated intent`() = runBlockingTest { whenever(controller.isEnabledForLockScreenButton).thenReturn(true) - var latest: KeyguardQuickAffordanceConfig.State? = null - val job = underTest.state.onEach { latest = it }.launchIn(this) + var latest: KeyguardQuickAffordanceConfig.LockScreenState? = null + val job = underTest.lockScreenState.onEach { latest = it }.launchIn(this) val callbackCaptor = argumentCaptor<QRCodeScannerController.Callback>() verify(controller).addCallback(callbackCaptor.capture()) @@ -93,8 +93,8 @@ class QrCodeScannerKeyguardQuickAffordanceConfigTest : SysuiTestCase() { @Test fun `affordance - scanner preference changed - delivers visible model`() = runBlockingTest { - var latest: KeyguardQuickAffordanceConfig.State? = null - val job = underTest.state.onEach { latest = it }.launchIn(this) + var latest: KeyguardQuickAffordanceConfig.LockScreenState? = null + val job = underTest.lockScreenState.onEach { latest = it }.launchIn(this) val callbackCaptor = argumentCaptor<QRCodeScannerController.Callback>() verify(controller).addCallback(callbackCaptor.capture()) @@ -109,34 +109,35 @@ class QrCodeScannerKeyguardQuickAffordanceConfigTest : SysuiTestCase() { @Test fun `affordance - scanner preference changed - delivers none`() = runBlockingTest { - var latest: KeyguardQuickAffordanceConfig.State? = null - val job = underTest.state.onEach { latest = it }.launchIn(this) + var latest: KeyguardQuickAffordanceConfig.LockScreenState? = null + val job = underTest.lockScreenState.onEach { latest = it }.launchIn(this) val callbackCaptor = argumentCaptor<QRCodeScannerController.Callback>() verify(controller).addCallback(callbackCaptor.capture()) whenever(controller.isEnabledForLockScreenButton).thenReturn(false) callbackCaptor.value.onQRCodeScannerPreferenceChanged() - assertThat(latest).isEqualTo(KeyguardQuickAffordanceConfig.State.Hidden) + assertThat(latest).isEqualTo(KeyguardQuickAffordanceConfig.LockScreenState.Hidden) job.cancel() verify(controller).removeCallback(callbackCaptor.value) } @Test - fun onQuickAffordanceClicked() { - assertThat(underTest.onQuickAffordanceClicked(mock())) + fun onQuickAffordanceTriggered() { + assertThat(underTest.onTriggered(mock())) .isEqualTo( - OnClickedResult.StartActivity( + OnTriggeredResult.StartActivity( intent = INTENT_1, canShowWhileLocked = true, ) ) } - private fun assertVisibleState(latest: KeyguardQuickAffordanceConfig.State?) { - assertThat(latest).isInstanceOf(KeyguardQuickAffordanceConfig.State.Visible::class.java) - val visibleState = latest as KeyguardQuickAffordanceConfig.State.Visible + private fun assertVisibleState(latest: KeyguardQuickAffordanceConfig.LockScreenState?) { + assertThat(latest) + .isInstanceOf(KeyguardQuickAffordanceConfig.LockScreenState.Visible::class.java) + val visibleState = latest as KeyguardQuickAffordanceConfig.LockScreenState.Visible assertThat(visibleState.icon).isNotNull() assertThat(visibleState.icon.contentDescription).isNotNull() } diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfigTest.kt index ae9e3c7a6f04..c05beef6d624 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfigTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfigTest.kt @@ -67,11 +67,11 @@ class QuickAccessWalletKeyguardQuickAffordanceConfigTest : SysuiTestCase() { @Test fun `affordance - keyguard showing - has wallet card - visible model`() = runBlockingTest { setUpState() - var latest: KeyguardQuickAffordanceConfig.State? = null + var latest: KeyguardQuickAffordanceConfig.LockScreenState? = null - val job = underTest.state.onEach { latest = it }.launchIn(this) + val job = underTest.lockScreenState.onEach { latest = it }.launchIn(this) - val visibleModel = latest as KeyguardQuickAffordanceConfig.State.Visible + val visibleModel = latest as KeyguardQuickAffordanceConfig.LockScreenState.Visible assertThat(visibleModel.icon) .isEqualTo( Icon.Loaded( @@ -88,11 +88,11 @@ class QuickAccessWalletKeyguardQuickAffordanceConfigTest : SysuiTestCase() { @Test fun `affordance - wallet not enabled - model is none`() = runBlockingTest { setUpState(isWalletEnabled = false) - var latest: KeyguardQuickAffordanceConfig.State? = null + var latest: KeyguardQuickAffordanceConfig.LockScreenState? = null - val job = underTest.state.onEach { latest = it }.launchIn(this) + val job = underTest.lockScreenState.onEach { latest = it }.launchIn(this) - assertThat(latest).isEqualTo(KeyguardQuickAffordanceConfig.State.Hidden) + assertThat(latest).isEqualTo(KeyguardQuickAffordanceConfig.LockScreenState.Hidden) job.cancel() } @@ -100,11 +100,11 @@ class QuickAccessWalletKeyguardQuickAffordanceConfigTest : SysuiTestCase() { @Test fun `affordance - query not successful - model is none`() = runBlockingTest { setUpState(isWalletQuerySuccessful = false) - var latest: KeyguardQuickAffordanceConfig.State? = null + var latest: KeyguardQuickAffordanceConfig.LockScreenState? = null - val job = underTest.state.onEach { latest = it }.launchIn(this) + val job = underTest.lockScreenState.onEach { latest = it }.launchIn(this) - assertThat(latest).isEqualTo(KeyguardQuickAffordanceConfig.State.Hidden) + assertThat(latest).isEqualTo(KeyguardQuickAffordanceConfig.LockScreenState.Hidden) job.cancel() } @@ -112,11 +112,11 @@ class QuickAccessWalletKeyguardQuickAffordanceConfigTest : SysuiTestCase() { @Test fun `affordance - missing icon - model is none`() = runBlockingTest { setUpState(hasWalletIcon = false) - var latest: KeyguardQuickAffordanceConfig.State? = null + var latest: KeyguardQuickAffordanceConfig.LockScreenState? = null - val job = underTest.state.onEach { latest = it }.launchIn(this) + val job = underTest.lockScreenState.onEach { latest = it }.launchIn(this) - assertThat(latest).isEqualTo(KeyguardQuickAffordanceConfig.State.Hidden) + assertThat(latest).isEqualTo(KeyguardQuickAffordanceConfig.LockScreenState.Hidden) job.cancel() } @@ -124,24 +124,24 @@ class QuickAccessWalletKeyguardQuickAffordanceConfigTest : SysuiTestCase() { @Test fun `affordance - no selected card - model is none`() = runBlockingTest { setUpState(hasWalletIcon = false) - var latest: KeyguardQuickAffordanceConfig.State? = null + var latest: KeyguardQuickAffordanceConfig.LockScreenState? = null - val job = underTest.state.onEach { latest = it }.launchIn(this) + val job = underTest.lockScreenState.onEach { latest = it }.launchIn(this) - assertThat(latest).isEqualTo(KeyguardQuickAffordanceConfig.State.Hidden) + assertThat(latest).isEqualTo(KeyguardQuickAffordanceConfig.LockScreenState.Hidden) job.cancel() } @Test - fun onQuickAffordanceClicked() { + fun onQuickAffordanceTriggered() { val animationController: ActivityLaunchAnimator.Controller = mock() val expandable: Expandable = mock { whenever(this.activityLaunchController()).thenReturn(animationController) } - assertThat(underTest.onQuickAffordanceClicked(expandable)) - .isEqualTo(KeyguardQuickAffordanceConfig.OnClickedResult.Handled) + assertThat(underTest.onTriggered(expandable)) + .isEqualTo(KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled) verify(walletController) .startQuickAccessUiIntent( activityStarter, diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorParameterizedTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorParameterizedTest.kt index 114cf19d0837..7116cc101d3f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorParameterizedTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorParameterizedTest.kt @@ -248,29 +248,29 @@ class KeyguardQuickAffordanceInteractorParameterizedTest : SysuiTestCase() { } @Test - fun onQuickAffordanceClicked() = runBlockingTest { + fun onQuickAffordanceTriggered() = runBlockingTest { setUpMocks( needStrongAuthAfterBoot = needStrongAuthAfterBoot, keyguardIsUnlocked = keyguardIsUnlocked, ) homeControls.setState( - state = - KeyguardQuickAffordanceConfig.State.Visible( + lockScreenState = + KeyguardQuickAffordanceConfig.LockScreenState.Visible( icon = DRAWABLE, ) ) - homeControls.onClickedResult = + homeControls.onTriggeredResult = if (startActivity) { - KeyguardQuickAffordanceConfig.OnClickedResult.StartActivity( + KeyguardQuickAffordanceConfig.OnTriggeredResult.StartActivity( intent = INTENT, canShowWhileLocked = canShowWhileLocked, ) } else { - KeyguardQuickAffordanceConfig.OnClickedResult.Handled + KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled } - underTest.onQuickAffordanceClicked( + underTest.onQuickAffordanceTriggered( configKey = BuiltInKeyguardQuickAffordanceKeys.HOME_CONTROLS, expandable = expandable, ) diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt index 1a1ee8aca099..ae32ba6676be 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt @@ -28,8 +28,8 @@ import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanc import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository import com.android.systemui.keyguard.domain.model.KeyguardQuickAffordanceModel import com.android.systemui.keyguard.domain.quickaffordance.FakeKeyguardQuickAffordanceRegistry +import com.android.systemui.keyguard.shared.quickaffordance.ActivationState import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordancePosition -import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordanceToggleState import com.android.systemui.plugins.ActivityStarter import com.android.systemui.settings.UserTracker import com.android.systemui.statusbar.policy.KeyguardStateController @@ -114,9 +114,9 @@ class KeyguardQuickAffordanceInteractorTest : SysuiTestCase() { fun `quickAffordance - bottom start affordance is visible`() = runBlockingTest { val configKey = BuiltInKeyguardQuickAffordanceKeys.HOME_CONTROLS homeControls.setState( - KeyguardQuickAffordanceConfig.State.Visible( + KeyguardQuickAffordanceConfig.LockScreenState.Visible( icon = ICON, - toggle = KeyguardQuickAffordanceToggleState.On, + activationState = ActivationState.Active, ) ) @@ -137,7 +137,7 @@ class KeyguardQuickAffordanceInteractorTest : SysuiTestCase() { assertThat(visibleModel.icon).isEqualTo(ICON) assertThat(visibleModel.icon.contentDescription) .isEqualTo(ContentDescription.Resource(res = CONTENT_DESCRIPTION_RESOURCE_ID)) - assertThat(visibleModel.toggle).isEqualTo(KeyguardQuickAffordanceToggleState.On) + assertThat(visibleModel.activationState).isEqualTo(ActivationState.Active) job.cancel() } @@ -145,7 +145,7 @@ class KeyguardQuickAffordanceInteractorTest : SysuiTestCase() { fun `quickAffordance - bottom end affordance is visible`() = runBlockingTest { val configKey = BuiltInKeyguardQuickAffordanceKeys.QUICK_ACCESS_WALLET quickAccessWallet.setState( - KeyguardQuickAffordanceConfig.State.Visible( + KeyguardQuickAffordanceConfig.LockScreenState.Visible( icon = ICON, ) ) @@ -167,7 +167,7 @@ class KeyguardQuickAffordanceInteractorTest : SysuiTestCase() { assertThat(visibleModel.icon).isEqualTo(ICON) assertThat(visibleModel.icon.contentDescription) .isEqualTo(ContentDescription.Resource(res = CONTENT_DESCRIPTION_RESOURCE_ID)) - assertThat(visibleModel.toggle).isEqualTo(KeyguardQuickAffordanceToggleState.NotSupported) + assertThat(visibleModel.activationState).isEqualTo(ActivationState.NotSupported) job.cancel() } @@ -175,7 +175,7 @@ class KeyguardQuickAffordanceInteractorTest : SysuiTestCase() { fun `quickAffordance - bottom start affordance hidden while dozing`() = runBlockingTest { repository.setDozing(true) homeControls.setState( - KeyguardQuickAffordanceConfig.State.Visible( + KeyguardQuickAffordanceConfig.LockScreenState.Visible( icon = ICON, ) ) @@ -195,7 +195,7 @@ class KeyguardQuickAffordanceInteractorTest : SysuiTestCase() { runBlockingTest { repository.setKeyguardShowing(false) homeControls.setState( - KeyguardQuickAffordanceConfig.State.Visible( + KeyguardQuickAffordanceConfig.LockScreenState.Visible( icon = ICON, ) ) diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt index f9be067362d3..f73d1ecf9373 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt @@ -31,8 +31,8 @@ import com.android.systemui.keyguard.domain.interactor.KeyguardBottomAreaInterac import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardQuickAffordanceInteractor import com.android.systemui.keyguard.domain.quickaffordance.FakeKeyguardQuickAffordanceRegistry +import com.android.systemui.keyguard.shared.quickaffordance.ActivationState import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordancePosition -import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordanceToggleState import com.android.systemui.plugins.ActivityStarter import com.android.systemui.settings.UserTracker import com.android.systemui.statusbar.policy.KeyguardStateController @@ -508,28 +508,28 @@ class KeyguardBottomAreaViewModelTest : SysuiTestCase() { KeyguardQuickAffordancePosition.BOTTOM_END -> quickAccessWalletAffordanceConfig } - val state = + val lockScreenState = if (testConfig.isVisible) { if (testConfig.intent != null) { - config.onClickedResult = - KeyguardQuickAffordanceConfig.OnClickedResult.StartActivity( + config.onTriggeredResult = + KeyguardQuickAffordanceConfig.OnTriggeredResult.StartActivity( intent = testConfig.intent, canShowWhileLocked = testConfig.canShowWhileLocked, ) } - KeyguardQuickAffordanceConfig.State.Visible( + KeyguardQuickAffordanceConfig.LockScreenState.Visible( icon = testConfig.icon ?: error("Icon is unexpectedly null!"), - toggle = + activationState = when (testConfig.isActivated) { - true -> KeyguardQuickAffordanceToggleState.On - false -> KeyguardQuickAffordanceToggleState.Off - null -> KeyguardQuickAffordanceToggleState.NotSupported + true -> ActivationState.Active + false -> ActivationState.Inactive + null -> ActivationState.NotSupported } ) } else { - KeyguardQuickAffordanceConfig.State.Hidden + KeyguardQuickAffordanceConfig.LockScreenState.Hidden } - config.setState(state) + config.setState(lockScreenState) return config.key } diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaHierarchyManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaHierarchyManagerTest.kt index 071604dc5790..920801f95f5b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaHierarchyManagerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaHierarchyManagerTest.kt @@ -31,7 +31,7 @@ import com.android.systemui.dreams.DreamOverlayStateController import com.android.systemui.keyguard.WakefulnessLifecycle import com.android.systemui.media.dream.MediaDreamComplication import com.android.systemui.plugins.statusbar.StatusBarStateController -import com.android.systemui.shade.testing.FakeNotifPanelEvents +import com.android.systemui.shade.ShadeExpansionStateManager import com.android.systemui.statusbar.StatusBarState import com.android.systemui.statusbar.SysuiStatusBarStateController import com.android.systemui.statusbar.phone.KeyguardBypassController @@ -89,7 +89,7 @@ class MediaHierarchyManagerTest : SysuiTestCase() { private lateinit var mediaHierarchyManager: MediaHierarchyManager private lateinit var mediaFrame: ViewGroup private val configurationController = FakeConfigurationController() - private val notifPanelEvents = FakeNotifPanelEvents() + private val notifPanelEvents = ShadeExpansionStateManager() private val settings = FakeSettings() private lateinit var testableLooper: TestableLooper private lateinit var fakeHandler: FakeHandler @@ -346,7 +346,7 @@ class MediaHierarchyManagerTest : SysuiTestCase() { @Test fun isCurrentlyInGuidedTransformation_hostsVisible_expandImmediateEnabled_returnsFalse() { - notifPanelEvents.changeExpandImmediate(expandImmediate = true) + notifPanelEvents.notifyExpandImmediateChange(true) goToLockscreen() enterGuidedTransformation() whenever(lockHost.visible).thenReturn(true) diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderCoordinatorTest.kt index fdeb3f5eb857..ad19bc2a80e0 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderCoordinatorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderCoordinatorTest.kt @@ -45,6 +45,7 @@ import com.android.systemui.statusbar.CommandQueue import com.android.systemui.statusbar.VibratorHelper import com.android.systemui.statusbar.policy.ConfigurationController import com.android.systemui.temporarydisplay.chipbar.ChipbarCoordinator +import com.android.systemui.temporarydisplay.chipbar.ChipbarLogger import com.android.systemui.temporarydisplay.chipbar.FakeChipbarCoordinator import com.android.systemui.util.concurrency.FakeExecutor import com.android.systemui.util.mockito.any @@ -80,6 +81,7 @@ class MediaTttSenderCoordinatorTest : SysuiTestCase() { @Mock private lateinit var configurationController: ConfigurationController @Mock private lateinit var falsingManager: FalsingManager @Mock private lateinit var falsingCollector: FalsingCollector + @Mock private lateinit var chipbarLogger: ChipbarLogger @Mock private lateinit var logger: MediaTttLogger @Mock private lateinit var mediaTttFlags: MediaTttFlags @Mock private lateinit var packageManager: PackageManager @@ -122,7 +124,7 @@ class MediaTttSenderCoordinatorTest : SysuiTestCase() { chipbarCoordinator = FakeChipbarCoordinator( context, - logger, + chipbarLogger, windowManager, fakeExecutor, accessibilityManager, diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java index 02f28a235b95..300843f3da95 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java @@ -438,8 +438,6 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase { when(mSysUiState.setFlag(anyInt(), anyBoolean())).thenReturn(mSysUiState); mMainHandler = new Handler(Looper.getMainLooper()); - NotificationPanelViewController.PanelEventsEmitter panelEventsEmitter = - new NotificationPanelViewController.PanelEventsEmitter(); mNotificationPanelViewController = new NotificationPanelViewController( mView, @@ -495,7 +493,6 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase { () -> mKeyguardBottomAreaViewController, mKeyguardUnlockAnimationController, mNotificationListContainer, - panelEventsEmitter, mNotificationStackSizeCalculator, mUnlockedScreenOffAnimationController, mShadeTransitionController, diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/testing/FakeNotifPanelEvents.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/testing/FakeNotifPanelEvents.kt deleted file mode 100644 index d05213877232..000000000000 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/testing/FakeNotifPanelEvents.kt +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2022 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.shade.testing - -import com.android.systemui.shade.NotifPanelEvents - -/** Fake implementation of [NotifPanelEvents] for testing. */ -class FakeNotifPanelEvents : NotifPanelEvents { - - private val listeners = mutableListOf<NotifPanelEvents.Listener>() - - override fun registerListener(listener: NotifPanelEvents.Listener) { - listeners.add(listener) - } - - override fun unregisterListener(listener: NotifPanelEvents.Listener) { - listeners.remove(listener) - } - - fun changeExpandImmediate(expandImmediate: Boolean) { - listeners.forEach { it.onExpandImmediateChanged(expandImmediate) } - } -} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinatorTest.java index c961cec39208..b4a5f5ce205f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinatorTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinatorTest.java @@ -36,7 +36,8 @@ import com.android.systemui.SysuiTestCase; import com.android.systemui.dump.DumpManager; import com.android.systemui.keyguard.WakefulnessLifecycle; import com.android.systemui.plugins.statusbar.StatusBarStateController; -import com.android.systemui.shade.NotifPanelEvents; +import com.android.systemui.shade.ShadeStateEvents; +import com.android.systemui.shade.ShadeStateEvents.ShadeStateEventsListener; import com.android.systemui.statusbar.notification.collection.GroupEntry; import com.android.systemui.statusbar.notification.collection.GroupEntryBuilder; import com.android.systemui.statusbar.notification.collection.NotifPipeline; @@ -71,12 +72,12 @@ public class VisualStabilityCoordinatorTest extends SysuiTestCase { @Mock private StatusBarStateController mStatusBarStateController; @Mock private Pluggable.PluggableListener<NotifStabilityManager> mInvalidateListener; @Mock private HeadsUpManager mHeadsUpManager; - @Mock private NotifPanelEvents mNotifPanelEvents; + @Mock private ShadeStateEvents mShadeStateEvents; @Mock private VisualStabilityProvider mVisualStabilityProvider; @Captor private ArgumentCaptor<WakefulnessLifecycle.Observer> mWakefulnessObserverCaptor; @Captor private ArgumentCaptor<StatusBarStateController.StateListener> mSBStateListenerCaptor; - @Captor private ArgumentCaptor<NotifPanelEvents.Listener> mNotifPanelEventsCallbackCaptor; + @Captor private ArgumentCaptor<ShadeStateEventsListener> mNotifPanelEventsCallbackCaptor; @Captor private ArgumentCaptor<NotifStabilityManager> mNotifStabilityManagerCaptor; private FakeSystemClock mFakeSystemClock = new FakeSystemClock(); @@ -84,7 +85,7 @@ public class VisualStabilityCoordinatorTest extends SysuiTestCase { private WakefulnessLifecycle.Observer mWakefulnessObserver; private StatusBarStateController.StateListener mStatusBarStateListener; - private NotifPanelEvents.Listener mNotifPanelEventsCallback; + private ShadeStateEvents.ShadeStateEventsListener mNotifPanelEventsCallback; private NotifStabilityManager mNotifStabilityManager; private NotificationEntry mEntry; private GroupEntry mGroupEntry; @@ -97,7 +98,7 @@ public class VisualStabilityCoordinatorTest extends SysuiTestCase { mFakeExecutor, mDumpManager, mHeadsUpManager, - mNotifPanelEvents, + mShadeStateEvents, mStatusBarStateController, mVisualStabilityProvider, mWakefulnessLifecycle); @@ -111,7 +112,8 @@ public class VisualStabilityCoordinatorTest extends SysuiTestCase { verify(mStatusBarStateController).addCallback(mSBStateListenerCaptor.capture()); mStatusBarStateListener = mSBStateListenerCaptor.getValue(); - verify(mNotifPanelEvents).registerListener(mNotifPanelEventsCallbackCaptor.capture()); + verify(mShadeStateEvents).addShadeStateEventsListener( + mNotifPanelEventsCallbackCaptor.capture()); mNotifPanelEventsCallback = mNotifPanelEventsCallbackCaptor.getValue(); verify(mNotifPipeline).setVisualStabilityManager(mNotifStabilityManagerCaptor.capture()); diff --git a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayControllerTest.kt index b68eb88d46db..91b5c35d9661 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayControllerTest.kt @@ -41,6 +41,7 @@ import org.junit.Test import org.mockito.Mock import org.mockito.Mockito.never import org.mockito.Mockito.reset +import org.mockito.Mockito.times import org.mockito.Mockito.verify import org.mockito.Mockito.`when` as whenever import org.mockito.MockitoAnnotations @@ -85,10 +86,29 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() { } @Test - fun displayView_viewAdded() { - underTest.displayView(getState()) + fun displayView_viewAddedWithCorrectTitle() { + underTest.displayView( + ViewInfo( + name = "name", + windowTitle = "Fake Window Title", + ) + ) - verify(windowManager).addView(any(), any()) + val windowParamsCaptor = argumentCaptor<WindowManager.LayoutParams>() + verify(windowManager).addView(any(), capture(windowParamsCaptor)) + assertThat(windowParamsCaptor.value!!.title).isEqualTo("Fake Window Title") + } + + @Test + fun displayView_logged() { + underTest.displayView( + ViewInfo( + name = "name", + windowTitle = "Fake Window Title", + ) + ) + + verify(logger).logViewAddition("Fake Window Title") } @Test @@ -110,7 +130,7 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() { } @Test - fun displayView_twice_viewNotAddedTwice() { + fun displayView_twiceWithSameWindowTitle_viewNotAddedTwice() { underTest.displayView(getState()) reset(windowManager) @@ -119,6 +139,32 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() { } @Test + fun displayView_twiceWithDifferentWindowTitles_oldViewRemovedNewViewAdded() { + underTest.displayView( + ViewInfo( + name = "name", + windowTitle = "First Fake Window Title", + ) + ) + + underTest.displayView( + ViewInfo( + name = "name", + windowTitle = "Second Fake Window Title", + ) + ) + + val viewCaptor = argumentCaptor<View>() + val windowParamsCaptor = argumentCaptor<WindowManager.LayoutParams>() + + verify(windowManager, times(2)).addView(capture(viewCaptor), capture(windowParamsCaptor)) + + assertThat(windowParamsCaptor.allValues[0].title).isEqualTo("First Fake Window Title") + assertThat(windowParamsCaptor.allValues[1].title).isEqualTo("Second Fake Window Title") + verify(windowManager).removeView(viewCaptor.allValues[0]) + } + + @Test fun displayView_viewDoesNotDisappearsBeforeTimeout() { val state = getState() underTest.displayView(state) @@ -197,7 +243,7 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() { underTest.removeView(reason) verify(windowManager).removeView(any()) - verify(logger).logChipRemoval(reason) + verify(logger).logViewRemoval(reason) } @Test @@ -232,8 +278,6 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() { configurationController, powerManager, R.layout.chipbar, - "Window Title", - "WAKE_REASON", ) { var mostRecentViewInfo: ViewInfo? = null @@ -250,9 +294,12 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() { } } - inner class ViewInfo(val name: String) : TemporaryViewInfo { - override fun getTimeoutMs() = 1L - } + inner class ViewInfo( + val name: String, + override val windowTitle: String = "Window Title", + override val wakeReason: String = "WAKE_REASON", + override val timeoutMs: Int = 1 + ) : TemporaryViewInfo() } private const val TIMEOUT_MS = 10000L diff --git a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewLoggerTest.kt index 13e9f608158e..d155050ce932 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewLoggerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewLoggerTest.kt @@ -43,20 +43,21 @@ class TemporaryViewLoggerTest : SysuiTestCase() { } @Test - fun logChipAddition_bufferHasLog() { - logger.logChipAddition() + fun logViewAddition_bufferHasLog() { + logger.logViewAddition("Test Window Title") val stringWriter = StringWriter() buffer.dump(PrintWriter(stringWriter), tailLength = 0) val actualString = stringWriter.toString() assertThat(actualString).contains(TAG) + assertThat(actualString).contains("Test Window Title") } @Test - fun logChipRemoval_bufferHasTagAndReason() { + fun logViewRemoval_bufferHasTagAndReason() { val reason = "test reason" - logger.logChipRemoval(reason) + logger.logViewRemoval(reason) val stringWriter = StringWriter() buffer.dump(PrintWriter(stringWriter), tailLength = 0) diff --git a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinatorTest.kt index 9fbf159ec348..f64397325867 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinatorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinatorTest.kt @@ -35,12 +35,12 @@ import com.android.systemui.common.shared.model.ContentDescription import com.android.systemui.common.shared.model.ContentDescription.Companion.loadContentDescription import com.android.systemui.common.shared.model.Icon import com.android.systemui.common.shared.model.Text -import com.android.systemui.media.taptotransfer.common.MediaTttLogger import com.android.systemui.plugins.FalsingManager import com.android.systemui.statusbar.VibratorHelper import com.android.systemui.statusbar.policy.ConfigurationController import com.android.systemui.util.concurrency.FakeExecutor import com.android.systemui.util.mockito.any +import com.android.systemui.util.mockito.eq import com.android.systemui.util.time.FakeSystemClock import com.android.systemui.util.view.ViewUtil import com.google.common.truth.Truth.assertThat @@ -60,7 +60,7 @@ import org.mockito.MockitoAnnotations class ChipbarCoordinatorTest : SysuiTestCase() { private lateinit var underTest: FakeChipbarCoordinator - @Mock private lateinit var logger: MediaTttLogger + @Mock private lateinit var logger: ChipbarLogger @Mock private lateinit var accessibilityManager: AccessibilityManager @Mock private lateinit var configurationController: ConfigurationController @Mock private lateinit var powerManager: PowerManager @@ -105,7 +105,7 @@ class ChipbarCoordinatorTest : SysuiTestCase() { val drawable = context.getDrawable(R.drawable.ic_celebration)!! underTest.displayView( - ChipbarInfo( + createChipbarInfo( Icon.Loaded(drawable, contentDescription = ContentDescription.Loaded("loadedCD")), Text.Loaded("text"), endItem = null, @@ -121,7 +121,7 @@ class ChipbarCoordinatorTest : SysuiTestCase() { fun displayView_resourceIcon_correctlyRendered() { val contentDescription = ContentDescription.Resource(R.string.controls_error_timeout) underTest.displayView( - ChipbarInfo( + createChipbarInfo( Icon.Resource(R.drawable.ic_cake, contentDescription), Text.Loaded("text"), endItem = null, @@ -136,7 +136,7 @@ class ChipbarCoordinatorTest : SysuiTestCase() { @Test fun displayView_loadedText_correctlyRendered() { underTest.displayView( - ChipbarInfo( + createChipbarInfo( Icon.Resource(R.id.check_box, null), Text.Loaded("display view text here"), endItem = null, @@ -149,7 +149,7 @@ class ChipbarCoordinatorTest : SysuiTestCase() { @Test fun displayView_resourceText_correctlyRendered() { underTest.displayView( - ChipbarInfo( + createChipbarInfo( Icon.Resource(R.id.check_box, null), Text.Resource(R.string.screenrecord_start_error), endItem = null, @@ -163,7 +163,7 @@ class ChipbarCoordinatorTest : SysuiTestCase() { @Test fun displayView_endItemNull_correctlyRendered() { underTest.displayView( - ChipbarInfo( + createChipbarInfo( Icon.Resource(R.id.check_box, null), Text.Loaded("text"), endItem = null, @@ -179,7 +179,7 @@ class ChipbarCoordinatorTest : SysuiTestCase() { @Test fun displayView_endItemLoading_correctlyRendered() { underTest.displayView( - ChipbarInfo( + createChipbarInfo( Icon.Resource(R.id.check_box, null), Text.Loaded("text"), endItem = ChipbarEndItem.Loading, @@ -195,7 +195,7 @@ class ChipbarCoordinatorTest : SysuiTestCase() { @Test fun displayView_endItemError_correctlyRendered() { underTest.displayView( - ChipbarInfo( + createChipbarInfo( Icon.Resource(R.id.check_box, null), Text.Loaded("text"), endItem = ChipbarEndItem.Error, @@ -211,7 +211,7 @@ class ChipbarCoordinatorTest : SysuiTestCase() { @Test fun displayView_endItemButton_correctlyRendered() { underTest.displayView( - ChipbarInfo( + createChipbarInfo( Icon.Resource(R.id.check_box, null), Text.Loaded("text"), endItem = @@ -237,7 +237,7 @@ class ChipbarCoordinatorTest : SysuiTestCase() { val buttonClickListener = View.OnClickListener { isClicked = true } underTest.displayView( - ChipbarInfo( + createChipbarInfo( Icon.Resource(R.id.check_box, null), Text.Loaded("text"), endItem = @@ -260,7 +260,7 @@ class ChipbarCoordinatorTest : SysuiTestCase() { val buttonClickListener = View.OnClickListener { isClicked = true } underTest.displayView( - ChipbarInfo( + createChipbarInfo( Icon.Resource(R.id.check_box, null), Text.Loaded("text"), endItem = @@ -279,7 +279,7 @@ class ChipbarCoordinatorTest : SysuiTestCase() { @Test fun displayView_vibrationEffect_doubleClickEffect() { underTest.displayView( - ChipbarInfo( + createChipbarInfo( Icon.Resource(R.id.check_box, null), Text.Loaded("text"), endItem = null, @@ -296,7 +296,7 @@ class ChipbarCoordinatorTest : SysuiTestCase() { val drawable = context.getDrawable(R.drawable.ic_celebration)!! underTest.displayView( - ChipbarInfo( + createChipbarInfo( Icon.Loaded(drawable, contentDescription = ContentDescription.Loaded("loadedCD")), Text.Loaded("title text"), endItem = ChipbarEndItem.Loading, @@ -314,7 +314,7 @@ class ChipbarCoordinatorTest : SysuiTestCase() { // WHEN the view is updated val newDrawable = context.getDrawable(R.drawable.ic_cake)!! underTest.updateView( - ChipbarInfo( + createChipbarInfo( Icon.Loaded(newDrawable, ContentDescription.Loaded("new CD")), Text.Loaded("new title text"), endItem = ChipbarEndItem.Error, @@ -331,6 +331,47 @@ class ChipbarCoordinatorTest : SysuiTestCase() { assertThat(chipbarView.getEndButton().visibility).isEqualTo(View.GONE) } + @Test + fun viewUpdates_logged() { + val drawable = context.getDrawable(R.drawable.ic_celebration)!! + underTest.displayView( + createChipbarInfo( + Icon.Loaded(drawable, contentDescription = ContentDescription.Loaded("loadedCD")), + Text.Loaded("title text"), + endItem = ChipbarEndItem.Loading, + ) + ) + + verify(logger).logViewUpdate(eq(WINDOW_TITLE), eq("title text"), any()) + + underTest.displayView( + createChipbarInfo( + Icon.Loaded(drawable, ContentDescription.Loaded("new CD")), + Text.Loaded("new title text"), + endItem = ChipbarEndItem.Error, + ) + ) + + verify(logger).logViewUpdate(eq(WINDOW_TITLE), eq("new title text"), any()) + } + + private fun createChipbarInfo( + startIcon: Icon, + text: Text, + endItem: ChipbarEndItem?, + vibrationEffect: VibrationEffect? = null, + ): ChipbarInfo { + return ChipbarInfo( + startIcon, + text, + endItem, + vibrationEffect, + windowTitle = WINDOW_TITLE, + wakeReason = WAKE_REASON, + timeoutMs = TIMEOUT, + ) + } + private fun ViewGroup.getStartIconView() = this.requireViewById<ImageView>(R.id.start_icon) private fun ViewGroup.getChipText(): String = @@ -350,3 +391,5 @@ class ChipbarCoordinatorTest : SysuiTestCase() { } private const val TIMEOUT = 10000 +private const val WINDOW_TITLE = "Test Chipbar Window Title" +private const val WAKE_REASON = "TEST_CHIPBAR_WAKE_REASON" diff --git a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/chipbar/FakeChipbarCoordinator.kt b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/chipbar/FakeChipbarCoordinator.kt index 17d402319246..574f70e7fddc 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/chipbar/FakeChipbarCoordinator.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/chipbar/FakeChipbarCoordinator.kt @@ -22,8 +22,6 @@ import android.view.ViewGroup import android.view.WindowManager import android.view.accessibility.AccessibilityManager import com.android.systemui.classifier.FalsingCollector -import com.android.systemui.media.taptotransfer.common.MediaTttLogger -import com.android.systemui.media.taptotransfer.receiver.MediaTttReceiverLogger import com.android.systemui.plugins.FalsingManager import com.android.systemui.statusbar.VibratorHelper import com.android.systemui.statusbar.policy.ConfigurationController @@ -33,7 +31,7 @@ import com.android.systemui.util.view.ViewUtil /** A fake implementation of [ChipbarCoordinator] for testing. */ class FakeChipbarCoordinator( context: Context, - @MediaTttReceiverLogger logger: MediaTttLogger, + logger: ChipbarLogger, windowManager: WindowManager, mainExecutor: DelayableExecutor, accessibilityManager: AccessibilityManager, diff --git a/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java b/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java index fc628cfdced2..000bafe1d650 100644 --- a/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java +++ b/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java @@ -44,6 +44,7 @@ import android.view.Display; import android.window.DisplayWindowPolicyController; import com.android.internal.annotations.GuardedBy; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.BlockedAppStreamingActivity; import java.util.List; @@ -112,7 +113,9 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController final ArraySet<Integer> mRunningUids = new ArraySet<>(); @Nullable private final ActivityListener mActivityListener; private final Handler mHandler = new Handler(Looper.getMainLooper()); - private final ArraySet<RunningAppsChangedListener> mRunningAppsChangedListener = + @NonNull + @GuardedBy("mGenericWindowPolicyControllerLock") + private final ArraySet<RunningAppsChangedListener> mRunningAppsChangedListeners = new ArraySet<>(); @Nullable private final @AssociationRequest.DeviceProfile String mDeviceProfile; @@ -178,12 +181,16 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController /** Register a listener for running applications changes. */ public void registerRunningAppsChangedListener(@NonNull RunningAppsChangedListener listener) { - mRunningAppsChangedListener.add(listener); + synchronized (mGenericWindowPolicyControllerLock) { + mRunningAppsChangedListeners.add(listener); + } } /** Unregister a listener for running applications changes. */ public void unregisterRunningAppsChangedListener(@NonNull RunningAppsChangedListener listener) { - mRunningAppsChangedListener.remove(listener); + synchronized (mGenericWindowPolicyControllerLock) { + mRunningAppsChangedListeners.remove(listener); + } } @Override @@ -283,12 +290,16 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController // Post callback on the main thread so it doesn't block activity launching mHandler.post(() -> mActivityListener.onDisplayEmpty(mDisplayId)); } - } - mHandler.post(() -> { - for (RunningAppsChangedListener listener : mRunningAppsChangedListener) { - listener.onRunningAppsChanged(runningUids); + if (!mRunningAppsChangedListeners.isEmpty()) { + final ArraySet<RunningAppsChangedListener> listeners = + new ArraySet<>(mRunningAppsChangedListeners); + mHandler.post(() -> { + for (RunningAppsChangedListener listener : listeners) { + listener.onRunningAppsChanged(runningUids); + } + }); } - }); + } } @Override @@ -354,4 +365,11 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController } return true; } + + @VisibleForTesting + int getRunningAppsChangedListenersSizeForTesting() { + synchronized (mGenericWindowPolicyControllerLock) { + return mRunningAppsChangedListeners.size(); + } + } } diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java index c59ee83aa895..bbffc894ef3e 100644 --- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java +++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java @@ -344,7 +344,7 @@ import java.util.concurrent.atomic.AtomicBoolean; if (AudioService.DEBUG_COMM_RTE) { Log.v(TAG, "setCommunicationRouteForClient: device: " + device); } - AudioService.sDeviceLogger.log((new EventLogger.StringEvent( + AudioService.sDeviceLogger.enqueue((new EventLogger.StringEvent( "setCommunicationRouteForClient for pid: " + pid + " device: " + device + " from API: " + eventSource)).printLog(TAG)); @@ -1212,7 +1212,7 @@ import java.util.concurrent.atomic.AtomicBoolean; if (useCase == AudioSystem.FOR_MEDIA) { postReportNewRoutes(fromA2dp); } - AudioService.sForceUseLogger.log( + AudioService.sForceUseLogger.enqueue( new AudioServiceEvents.ForceUseEvent(useCase, config, eventSource)); new MediaMetrics.Item(MediaMetrics.Name.AUDIO_FORCE_USE + MediaMetrics.SEPARATOR + AudioSystem.forceUseUsageToString(useCase)) @@ -1230,7 +1230,7 @@ import java.util.concurrent.atomic.AtomicBoolean; } private void onSendBecomingNoisyIntent() { - AudioService.sDeviceLogger.log((new EventLogger.StringEvent( + AudioService.sDeviceLogger.enqueue((new EventLogger.StringEvent( "broadcast ACTION_AUDIO_BECOMING_NOISY")).printLog(TAG)); mSystemServer.sendDeviceBecomingNoisyIntent(); } @@ -1468,7 +1468,7 @@ import java.util.concurrent.atomic.AtomicBoolean; case MSG_L_BT_ACTIVE_DEVICE_CHANGE_EXT: { final BtDeviceInfo info = (BtDeviceInfo) msg.obj; if (info.mDevice == null) break; - AudioService.sDeviceLogger.log((new EventLogger.StringEvent( + AudioService.sDeviceLogger.enqueue((new EventLogger.StringEvent( "msg: onBluetoothActiveDeviceChange " + " state=" + info.mState // only querying address as this is the only readily available @@ -1858,7 +1858,7 @@ import java.util.concurrent.atomic.AtomicBoolean; Log.v(TAG, "onUpdateCommunicationRoute, preferredCommunicationDevice: " + preferredCommunicationDevice + " eventSource: " + eventSource); } - AudioService.sDeviceLogger.log((new EventLogger.StringEvent( + AudioService.sDeviceLogger.enqueue((new EventLogger.StringEvent( "onUpdateCommunicationRoute, preferredCommunicationDevice: " + preferredCommunicationDevice + " eventSource: " + eventSource))); diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java index ce36ff829693..c8f282fd576e 100644 --- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java +++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java @@ -309,7 +309,7 @@ public class AudioDeviceInventory { address = ""; } - AudioService.sDeviceLogger.log(new EventLogger.StringEvent("BT connected:" + AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent("BT connected:" + " addr=" + address + " profile=" + btInfo.mProfile + " state=" + btInfo.mState @@ -412,13 +412,13 @@ public class AudioDeviceInventory { if (!BluetoothAdapter.checkBluetoothAddress(address)) { address = ""; } - AudioService.sDeviceLogger.log(new EventLogger.StringEvent( + AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent( "onBluetoothA2dpDeviceConfigChange addr=" + address + " event=" + BtHelper.a2dpDeviceEventToString(event))); synchronized (mDevicesLock) { if (mDeviceBroker.hasScheduledA2dpConnection(btDevice)) { - AudioService.sDeviceLogger.log(new EventLogger.StringEvent( + AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent( "A2dp config change ignored (scheduled connection change)") .printLog(TAG)); mmi.set(MediaMetrics.Property.EARLY_RETURN, "A2dp config change ignored") @@ -460,7 +460,7 @@ public class AudioDeviceInventory { BtHelper.getName(btDevice), a2dpCodec); if (res != AudioSystem.AUDIO_STATUS_OK) { - AudioService.sDeviceLogger.log(new EventLogger.StringEvent( + AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent( "APM handleDeviceConfigChange failed for A2DP device addr=" + address + " codec=" + AudioSystem.audioFormatToString(a2dpCodec)) .printLog(TAG)); @@ -472,7 +472,7 @@ public class AudioDeviceInventory { BluetoothProfile.A2DP, BluetoothProfile.STATE_DISCONNECTED, musicDevice, AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP)); } else { - AudioService.sDeviceLogger.log(new EventLogger.StringEvent( + AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent( "APM handleDeviceConfigChange success for A2DP device addr=" + address + " codec=" + AudioSystem.audioFormatToString(a2dpCodec)) .printLog(TAG)); @@ -522,7 +522,7 @@ public class AudioDeviceInventory { AudioDeviceInventory.WiredDeviceConnectionState wdcs) { int type = wdcs.mAttributes.getInternalType(); - AudioService.sDeviceLogger.log(new AudioServiceEvents.WiredDevConnectEvent(wdcs)); + AudioService.sDeviceLogger.enqueue(new AudioServiceEvents.WiredDevConnectEvent(wdcs)); MediaMetrics.Item mmi = new MediaMetrics.Item(mMetricsId + "onSetWiredDeviceConnectionState") @@ -619,7 +619,7 @@ public class AudioDeviceInventory { @NonNull List<AudioDeviceAttributes> devices) { final long identity = Binder.clearCallingIdentity(); - AudioService.sDeviceLogger.log((new EventLogger.StringEvent( + AudioService.sDeviceLogger.enqueue((new EventLogger.StringEvent( "setPreferredDevicesForStrategySync, strategy: " + strategy + " devices: " + devices)).printLog(TAG)); final int status = mAudioSystem.setDevicesRoleForStrategy( @@ -635,7 +635,7 @@ public class AudioDeviceInventory { /*package*/ int removePreferredDevicesForStrategySync(int strategy) { final long identity = Binder.clearCallingIdentity(); - AudioService.sDeviceLogger.log((new EventLogger.StringEvent( + AudioService.sDeviceLogger.enqueue((new EventLogger.StringEvent( "removePreferredDevicesForStrategySync, strategy: " + strategy)).printLog(TAG)); @@ -1000,13 +1000,13 @@ public class AudioDeviceInventory { // TODO: log in MediaMetrics once distinction between connection failure and // double connection is made. if (res != AudioSystem.AUDIO_STATUS_OK) { - AudioService.sDeviceLogger.log(new EventLogger.StringEvent( + AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent( "APM failed to make available A2DP device addr=" + address + " error=" + res).printLog(TAG)); // TODO: connection failed, stop here // TODO: return; } else { - AudioService.sDeviceLogger.log(new EventLogger.StringEvent( + AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent( "A2DP device addr=" + address + " now available").printLog(TAG)); } @@ -1047,7 +1047,7 @@ public class AudioDeviceInventory { if (!deviceToRemoveKey .equals(mApmConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP))) { // removing A2DP device not currently used by AudioPolicy, log but don't act on it - AudioService.sDeviceLogger.log((new EventLogger.StringEvent( + AudioService.sDeviceLogger.enqueue((new EventLogger.StringEvent( "A2DP device " + address + " made unavailable, was not used")).printLog(TAG)); mmi.set(MediaMetrics.Property.EARLY_RETURN, "A2DP device made unavailable, was not used") @@ -1062,13 +1062,13 @@ public class AudioDeviceInventory { AudioSystem.DEVICE_STATE_UNAVAILABLE, a2dpCodec); if (res != AudioSystem.AUDIO_STATUS_OK) { - AudioService.sDeviceLogger.log(new EventLogger.StringEvent( + AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent( "APM failed to make unavailable A2DP device addr=" + address + " error=" + res).printLog(TAG)); // TODO: failed to disconnect, stop here // TODO: return; } else { - AudioService.sDeviceLogger.log((new EventLogger.StringEvent( + AudioService.sDeviceLogger.enqueue((new EventLogger.StringEvent( "A2DP device addr=" + address + " made unavailable")).printLog(TAG)); } mApmConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP); @@ -1314,7 +1314,7 @@ public class AudioDeviceInventory { && !mDeviceBroker.hasAudioFocusUsers()) { // no media playback, not a "becoming noisy" situation, otherwise it could cause // the pausing of some apps that are playing remotely - AudioService.sDeviceLogger.log((new EventLogger.StringEvent( + AudioService.sDeviceLogger.enqueue((new EventLogger.StringEvent( "dropping ACTION_AUDIO_BECOMING_NOISY")).printLog(TAG)); mmi.set(MediaMetrics.Property.DELAY_MS, 0).record(); // OK to return return 0; diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index f3a9a699b371..016bab08472a 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -990,7 +990,7 @@ public class AudioService extends IAudioService.Stub public AudioService(Context context, AudioSystemAdapter audioSystem, SystemServerAdapter systemServer, SettingsAdapter settings, @Nullable Looper looper, AppOpsManager appOps) { - sLifecycleLogger.log(new EventLogger.StringEvent("AudioService()")); + sLifecycleLogger.enqueue(new EventLogger.StringEvent("AudioService()")); mContext = context; mContentResolver = context.getContentResolver(); mAppOps = appOps; @@ -1539,14 +1539,14 @@ public class AudioService extends IAudioService.Stub if (!mSystemReady || (AudioSystem.checkAudioFlinger() != AudioSystem.AUDIO_STATUS_OK)) { Log.e(TAG, "Audioserver died."); - sLifecycleLogger.log(new EventLogger.StringEvent( + sLifecycleLogger.enqueue(new EventLogger.StringEvent( "onAudioServerDied() audioserver died")); sendMsg(mAudioHandler, MSG_AUDIO_SERVER_DIED, SENDMSG_NOOP, 0, 0, null, 500); return; } Log.i(TAG, "Audioserver started."); - sLifecycleLogger.log(new EventLogger.StringEvent( + sLifecycleLogger.enqueue(new EventLogger.StringEvent( "onAudioServerDied() audioserver started")); updateAudioHalPids(); @@ -1776,7 +1776,7 @@ public class AudioService extends IAudioService.Stub // did it work? check based on status if (status != AudioSystem.AUDIO_STATUS_OK) { - sLifecycleLogger.log(new EventLogger.StringEvent( + sLifecycleLogger.enqueue(new EventLogger.StringEvent( caller + ": initStreamVolume failed with " + status + " will retry") .printLog(ALOGE, TAG)); sendMsg(mAudioHandler, MSG_REINIT_VOLUMES, SENDMSG_NOOP, 0, 0, @@ -1790,7 +1790,7 @@ public class AudioService extends IAudioService.Stub } // success - sLifecycleLogger.log(new EventLogger.StringEvent( + sLifecycleLogger.enqueue(new EventLogger.StringEvent( caller + ": initStreamVolume succeeded").printLog(ALOGI, TAG)); } @@ -1813,7 +1813,7 @@ public class AudioService extends IAudioService.Stub } } if (!success) { - sLifecycleLogger.log(new EventLogger.StringEvent( + sLifecycleLogger.enqueue(new EventLogger.StringEvent( caller + ": initStreamVolume succeeded but invalid mix/max levels, will retry") .printLog(ALOGW, TAG)); sendMsg(mAudioHandler, MSG_REINIT_VOLUMES, SENDMSG_NOOP, 0, 0, @@ -2764,7 +2764,7 @@ public class AudioService extends IAudioService.Stub "setPreferredDeviceForStrategy u/pid:%d/%d strat:%d dev:%s", Binder.getCallingUid(), Binder.getCallingPid(), strategy, devices.stream().map(e -> e.toString()).collect(Collectors.joining(","))); - sDeviceLogger.log(new EventLogger.StringEvent(logString).printLog(TAG)); + sDeviceLogger.enqueue(new EventLogger.StringEvent(logString).printLog(TAG)); if (devices.stream().anyMatch(device -> device.getRole() == AudioDeviceAttributes.ROLE_INPUT)) { Log.e(TAG, "Unsupported input routing in " + logString); @@ -2784,7 +2784,7 @@ public class AudioService extends IAudioService.Stub public int removePreferredDevicesForStrategy(int strategy) { final String logString = String.format("removePreferredDeviceForStrategy strat:%d", strategy); - sDeviceLogger.log(new EventLogger.StringEvent(logString).printLog(TAG)); + sDeviceLogger.enqueue(new EventLogger.StringEvent(logString).printLog(TAG)); final int status = mDeviceBroker.removePreferredDevicesForStrategySync(strategy); if (status != AudioSystem.SUCCESS) { @@ -2850,7 +2850,7 @@ public class AudioService extends IAudioService.Stub "setPreferredDevicesForCapturePreset u/pid:%d/%d source:%d dev:%s", Binder.getCallingUid(), Binder.getCallingPid(), capturePreset, devices.stream().map(e -> e.toString()).collect(Collectors.joining(","))); - sDeviceLogger.log(new EventLogger.StringEvent(logString).printLog(TAG)); + sDeviceLogger.enqueue(new EventLogger.StringEvent(logString).printLog(TAG)); if (devices.stream().anyMatch(device -> device.getRole() == AudioDeviceAttributes.ROLE_OUTPUT)) { Log.e(TAG, "Unsupported output routing in " + logString); @@ -2871,7 +2871,7 @@ public class AudioService extends IAudioService.Stub public int clearPreferredDevicesForCapturePreset(int capturePreset) { final String logString = String.format( "removePreferredDeviceForCapturePreset source:%d", capturePreset); - sDeviceLogger.log(new EventLogger.StringEvent(logString).printLog(TAG)); + sDeviceLogger.enqueue(new EventLogger.StringEvent(logString).printLog(TAG)); final int status = mDeviceBroker.clearPreferredDevicesForCapturePresetSync(capturePreset); if (status != AudioSystem.SUCCESS) { @@ -3043,9 +3043,10 @@ public class AudioService extends IAudioService.Stub + ", volControlStream=" + mVolumeControlStream + ", userSelect=" + mUserSelectedVolumeControlStream); if (direction != AudioManager.ADJUST_SAME) { - sVolumeLogger.log(new VolumeEvent(VolumeEvent.VOL_ADJUST_SUGG_VOL, suggestedStreamType, - direction/*val1*/, flags/*val2*/, new StringBuilder(callingPackage) - .append("/").append(caller).append(" uid:").append(uid).toString())); + sVolumeLogger.enqueue( + new VolumeEvent(VolumeEvent.VOL_ADJUST_SUGG_VOL, suggestedStreamType, + direction/*val1*/, flags/*val2*/, new StringBuilder(callingPackage) + .append("/").append(caller).append(" uid:").append(uid).toString())); } boolean hasExternalVolumeController = notifyExternalVolumeController(direction); @@ -3144,7 +3145,7 @@ public class AudioService extends IAudioService.Stub return; } - sVolumeLogger.log(new VolumeEvent(VolumeEvent.VOL_ADJUST_STREAM_VOL, streamType, + sVolumeLogger.enqueue(new VolumeEvent(VolumeEvent.VOL_ADJUST_STREAM_VOL, streamType, direction/*val1*/, flags/*val2*/, callingPackage)); adjustStreamVolume(streamType, direction, flags, callingPackage, callingPackage, Binder.getCallingUid(), Binder.getCallingPid(), attributionTag, @@ -3625,7 +3626,7 @@ public class AudioService extends IAudioService.Stub } final VolumeGroupState vgs = sVolumeGroupStates.get(volumeGroup); - sVolumeLogger.log(new VolumeEvent(VolumeEvent.VOL_SET_GROUP_VOL, attr, vgs.name(), + sVolumeLogger.enqueue(new VolumeEvent(VolumeEvent.VOL_SET_GROUP_VOL, attr, vgs.name(), index/*val1*/, flags/*val2*/, callingPackage)); vgs.setVolumeIndex(index, flags); @@ -3776,7 +3777,7 @@ public class AudioService extends IAudioService.Stub ? new VolumeEvent(VolumeEvent.VOL_SET_STREAM_VOL, streamType, index/*val1*/, flags/*val2*/, callingPackage) : new DeviceVolumeEvent(streamType, index, device, callingPackage); - sVolumeLogger.log(event); + sVolumeLogger.enqueue(event); setStreamVolume(streamType, index, flags, device, callingPackage, callingPackage, attributionTag, Binder.getCallingUid(), callingOrSelfHasAudioSettingsPermission()); @@ -3977,7 +3978,7 @@ public class AudioService extends IAudioService.Stub private void updateHearingAidVolumeOnVoiceActivityUpdate() { final int streamType = getBluetoothContextualVolumeStream(); final int index = getStreamVolume(streamType); - sVolumeLogger.log(new VolumeEvent(VolumeEvent.VOL_VOICE_ACTIVITY_HEARING_AID, + sVolumeLogger.enqueue(new VolumeEvent(VolumeEvent.VOL_VOICE_ACTIVITY_HEARING_AID, mVoicePlaybackActive.get(), streamType, index)); mDeviceBroker.postSetHearingAidVolumeIndex(index * 10, streamType); @@ -4018,7 +4019,7 @@ public class AudioService extends IAudioService.Stub if (AudioSystem.isSingleAudioDeviceType( absVolumeMultiModeCaseDevices, AudioSystem.DEVICE_OUT_HEARING_AID)) { final int index = getStreamVolume(streamType); - sVolumeLogger.log(new VolumeEvent(VolumeEvent.VOL_MODE_CHANGE_HEARING_AID, + sVolumeLogger.enqueue(new VolumeEvent(VolumeEvent.VOL_MODE_CHANGE_HEARING_AID, newMode, streamType, index)); mDeviceBroker.postSetHearingAidVolumeIndex(index * 10, streamType); } @@ -5419,7 +5420,7 @@ public class AudioService extends IAudioService.Stub /*obj*/ null, /*delay*/ 0); int previousMode = mMode.getAndSet(mode); // Note: newModeOwnerPid is always 0 when actualMode is MODE_NORMAL - mModeLogger.log(new PhoneStateEvent(requesterPackage, requesterPid, + mModeLogger.enqueue(new PhoneStateEvent(requesterPackage, requesterPid, requestedMode, pid, mode)); int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE); @@ -5562,7 +5563,7 @@ public class AudioService extends IAudioService.Stub } if (direction != AudioManager.ADJUST_SAME) { - sVolumeLogger.log(new VolumeEvent(VolumeEvent.VOL_ADJUST_VOL_UID, streamType, + sVolumeLogger.enqueue(new VolumeEvent(VolumeEvent.VOL_ADJUST_VOL_UID, streamType, direction/*val1*/, flags/*val2*/, new StringBuilder(packageName).append(" uid:").append(uid) .toString())); @@ -6892,7 +6893,7 @@ public class AudioService extends IAudioService.Stub // verify arguments Objects.requireNonNull(device); AudioManager.enforceValidVolumeBehavior(deviceVolumeBehavior); - sVolumeLogger.log(new EventLogger.StringEvent("setDeviceVolumeBehavior: dev:" + sVolumeLogger.enqueue(new EventLogger.StringEvent("setDeviceVolumeBehavior: dev:" + AudioSystem.getOutputDeviceName(device.getInternalType()) + " addr:" + device.getAddress() + " behavior:" + AudioDeviceVolumeManager.volumeBehaviorName(deviceVolumeBehavior) @@ -6948,7 +6949,7 @@ public class AudioService extends IAudioService.Stub } // log event and caller - sDeviceLogger.log(new EventLogger.StringEvent( + sDeviceLogger.enqueue(new EventLogger.StringEvent( "Volume behavior " + deviceVolumeBehavior + " for dev=0x" + Integer.toHexString(audioSystemDeviceOut) + " from:" + caller)); // make sure we have a volume entry for this device, and that volume is updated according @@ -7594,7 +7595,7 @@ public class AudioService extends IAudioService.Stub final int status = AudioSystem.initStreamVolume( streamType, mIndexMin / 10, mIndexMax / 10); if (status != AudioSystem.AUDIO_STATUS_OK) { - sLifecycleLogger.log(new EventLogger.StringEvent( + sLifecycleLogger.enqueue(new EventLogger.StringEvent( "VSS() stream:" + streamType + " initStreamVolume=" + status) .printLog(ALOGE, TAG)); sendMsg(mAudioHandler, MSG_REINIT_VOLUMES, SENDMSG_NOOP, 0, 0, @@ -8013,7 +8014,7 @@ public class AudioService extends IAudioService.Stub } } if (changed) { - sVolumeLogger.log(new VolumeEvent( + sVolumeLogger.enqueue(new VolumeEvent( VolumeEvent.VOL_MUTE_STREAM_INT, mStreamType, state)); } return changed; @@ -8183,10 +8184,10 @@ public class AudioService extends IAudioService.Stub streamState.setIndex(index, update.mDevice, update.mCaller, // trusted as index is always validated before message is posted true /*hasModifyAudioSettings*/); - sVolumeLogger.log(new EventLogger.StringEvent(update.mCaller + " dev:0x" + sVolumeLogger.enqueue(new EventLogger.StringEvent(update.mCaller + " dev:0x" + Integer.toHexString(update.mDevice) + " volIdx:" + index)); } else { - sVolumeLogger.log(new EventLogger.StringEvent(update.mCaller + sVolumeLogger.enqueue(new EventLogger.StringEvent(update.mCaller + " update vol on dev:0x" + Integer.toHexString(update.mDevice))); } setDeviceVolume(streamState, update.mDevice); @@ -8364,7 +8365,7 @@ public class AudioService extends IAudioService.Stub .set(MediaMetrics.Property.FORCE_USE_MODE, AudioSystem.forceUseConfigToString(config)) .record(); - sForceUseLogger.log( + sForceUseLogger.enqueue( new AudioServiceEvents.ForceUseEvent(useCase, config, eventSource)); mAudioSystem.setForceUse(useCase, config); } @@ -8633,7 +8634,7 @@ public class AudioService extends IAudioService.Stub private void avrcpSupportsAbsoluteVolume(String address, boolean support) { // address is not used for now, but may be used when multiple a2dp devices are supported - sVolumeLogger.log(new EventLogger.StringEvent("avrcpSupportsAbsoluteVolume addr=" + sVolumeLogger.enqueue(new EventLogger.StringEvent("avrcpSupportsAbsoluteVolume addr=" + address + " support=" + support).printLog(TAG)); mDeviceBroker.setAvrcpAbsoluteVolumeSupported(support); setAvrcpAbsoluteVolumeSupported(support); @@ -10668,7 +10669,7 @@ public class AudioService extends IAudioService.Stub pcb.asBinder().linkToDeath(app, 0/*flags*/); // logging after registration so we have the registration id - mDynPolicyLogger.log((new EventLogger.StringEvent("registerAudioPolicy for " + mDynPolicyLogger.enqueue((new EventLogger.StringEvent("registerAudioPolicy for " + pcb.asBinder() + " u/pid:" + Binder.getCallingUid() + "/" + Binder.getCallingPid() + " with config:" + app.toCompactLogString())) .printLog(TAG)); @@ -10866,7 +10867,7 @@ public class AudioService extends IAudioService.Stub private void unregisterAudioPolicyInt(@NonNull IAudioPolicyCallback pcb, String operationName) { - mDynPolicyLogger.log((new EventLogger.StringEvent(operationName + " for " + mDynPolicyLogger.enqueue((new EventLogger.StringEvent(operationName + " for " + pcb.asBinder()).printLog(TAG))); synchronized (mAudioPolicies) { AudioPolicyProxy app = mAudioPolicies.remove(pcb.asBinder()); @@ -11394,7 +11395,7 @@ public class AudioService extends IAudioService.Stub } public void binderDied() { - mDynPolicyLogger.log((new EventLogger.StringEvent("AudioPolicy " + mDynPolicyLogger.enqueue((new EventLogger.StringEvent("AudioPolicy " + mPolicyCallback.asBinder() + " died").printLog(TAG))); release(); } diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java index 399829e32588..df65dbd53e06 100644 --- a/services/core/java/com/android/server/audio/BtHelper.java +++ b/services/core/java/com/android/server/audio/BtHelper.java @@ -263,20 +263,20 @@ public class BtHelper { /*package*/ synchronized void setAvrcpAbsoluteVolumeIndex(int index) { if (mA2dp == null) { if (AudioService.DEBUG_VOL) { - AudioService.sVolumeLogger.log(new EventLogger.StringEvent( + AudioService.sVolumeLogger.enqueue(new EventLogger.StringEvent( "setAvrcpAbsoluteVolumeIndex: bailing due to null mA2dp").printLog(TAG)); return; } } if (!mAvrcpAbsVolSupported) { - AudioService.sVolumeLogger.log(new EventLogger.StringEvent( + AudioService.sVolumeLogger.enqueue(new EventLogger.StringEvent( "setAvrcpAbsoluteVolumeIndex: abs vol not supported ").printLog(TAG)); return; } if (AudioService.DEBUG_VOL) { Log.i(TAG, "setAvrcpAbsoluteVolumeIndex index=" + index); } - AudioService.sVolumeLogger.log(new AudioServiceEvents.VolumeEvent( + AudioService.sVolumeLogger.enqueue(new AudioServiceEvents.VolumeEvent( AudioServiceEvents.VolumeEvent.VOL_SET_AVRCP_VOL, index)); mA2dp.setAvrcpAbsoluteVolume(index); } @@ -393,14 +393,14 @@ public class BtHelper { @GuardedBy("AudioDeviceBroker.mDeviceStateLock") /*package*/ synchronized boolean startBluetoothSco(int scoAudioMode, @NonNull String eventSource) { - AudioService.sDeviceLogger.log(new EventLogger.StringEvent(eventSource)); + AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent(eventSource)); return requestScoState(BluetoothHeadset.STATE_AUDIO_CONNECTED, scoAudioMode); } // @GuardedBy("AudioDeviceBroker.mSetModeLock") @GuardedBy("AudioDeviceBroker.mDeviceStateLock") /*package*/ synchronized boolean stopBluetoothSco(@NonNull String eventSource) { - AudioService.sDeviceLogger.log(new EventLogger.StringEvent(eventSource)); + AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent(eventSource)); return requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, SCO_MODE_VIRTUAL_CALL); } @@ -418,7 +418,7 @@ public class BtHelper { Log.i(TAG, "setLeAudioVolume: calling mLeAudio.setVolume idx=" + index + " volume=" + volume); } - AudioService.sVolumeLogger.log(new AudioServiceEvents.VolumeEvent( + AudioService.sVolumeLogger.enqueue(new AudioServiceEvents.VolumeEvent( AudioServiceEvents.VolumeEvent.VOL_SET_LE_AUDIO_VOL, index, maxIndex)); mLeAudio.setVolume(volume); } @@ -443,7 +443,7 @@ public class BtHelper { } // do not log when hearing aid is not connected to avoid confusion when reading dumpsys if (isHeadAidConnected) { - AudioService.sVolumeLogger.log(new AudioServiceEvents.VolumeEvent( + AudioService.sVolumeLogger.enqueue(new AudioServiceEvents.VolumeEvent( AudioServiceEvents.VolumeEvent.VOL_SET_HEARING_AID_VOL, index, gainDB)); } mHearingAid.setVolume(gainDB); @@ -675,7 +675,7 @@ public class BtHelper { case BluetoothProfile.HEADSET: case BluetoothProfile.HEARING_AID: case BluetoothProfile.LE_AUDIO: - AudioService.sDeviceLogger.log(new EventLogger.StringEvent( + AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent( "BT profile service: connecting " + BluetoothProfile.getProfileName(profile) + " profile")); mDeviceBroker.postBtProfileConnected(profile, proxy); diff --git a/services/core/java/com/android/server/audio/FadeOutManager.java b/services/core/java/com/android/server/audio/FadeOutManager.java index e54ee869fef2..5f6f4b125710 100644 --- a/services/core/java/com/android/server/audio/FadeOutManager.java +++ b/services/core/java/com/android/server/audio/FadeOutManager.java @@ -245,7 +245,7 @@ public final class FadeOutManager { return; } try { - PlaybackActivityMonitor.sEventLogger.log( + PlaybackActivityMonitor.sEventLogger.enqueue( (new PlaybackActivityMonitor.FadeOutEvent(apc, skipRamp)).printLog(TAG)); apc.getPlayerProxy().applyVolumeShaper( FADEOUT_VSHAPE, @@ -262,7 +262,7 @@ public final class FadeOutManager { final AudioPlaybackConfiguration apc = players.get(piid); if (apc != null) { try { - PlaybackActivityMonitor.sEventLogger.log( + PlaybackActivityMonitor.sEventLogger.enqueue( (new EventLogger.StringEvent("unfading out piid:" + piid)).printLog(TAG)); apc.getPlayerProxy().applyVolumeShaper( diff --git a/services/core/java/com/android/server/audio/MediaFocusControl.java b/services/core/java/com/android/server/audio/MediaFocusControl.java index 1ca27dd7112c..27687b2612e5 100644 --- a/services/core/java/com/android/server/audio/MediaFocusControl.java +++ b/services/core/java/com/android/server/audio/MediaFocusControl.java @@ -185,7 +185,7 @@ public class MediaFocusControl implements PlayerFocusEnforcer { final FocusRequester focusOwner = stackIterator.next(); if (focusOwner.hasSameUid(uid) && focusOwner.hasSamePackage(packageName)) { clientsToRemove.add(focusOwner.getClientId()); - mEventLogger.log((new EventLogger.StringEvent( + mEventLogger.enqueue((new EventLogger.StringEvent( "focus owner:" + focusOwner.getClientId() + " in uid:" + uid + " pack: " + packageName + " getting AUDIOFOCUS_LOSS due to app suspension")) @@ -433,7 +433,7 @@ public class MediaFocusControl implements PlayerFocusEnforcer { FocusRequester fr = stackIterator.next(); if(fr.hasSameBinder(cb)) { Log.i(TAG, "AudioFocus removeFocusStackEntryOnDeath(): removing entry for " + cb); - mEventLogger.log(new EventLogger.StringEvent( + mEventLogger.enqueue(new EventLogger.StringEvent( "focus requester:" + fr.getClientId() + " in uid:" + fr.getClientUid() + " pack:" + fr.getPackageName() @@ -470,7 +470,7 @@ public class MediaFocusControl implements PlayerFocusEnforcer { final FocusRequester fr = owner.getValue(); if (fr.hasSameBinder(cb)) { ownerIterator.remove(); - mEventLogger.log(new EventLogger.StringEvent( + mEventLogger.enqueue(new EventLogger.StringEvent( "focus requester:" + fr.getClientId() + " in uid:" + fr.getClientUid() + " pack:" + fr.getPackageName() @@ -968,7 +968,7 @@ public class MediaFocusControl implements PlayerFocusEnforcer { // supposed to be alone in bitfield final int uid = (flags == AudioManager.AUDIOFOCUS_FLAG_TEST) ? testUid : Binder.getCallingUid(); - mEventLogger.log((new EventLogger.StringEvent( + mEventLogger.enqueue((new EventLogger.StringEvent( "requestAudioFocus() from uid/pid " + uid + "/" + Binder.getCallingPid() + " AA=" + aa.usageToString() + "/" + aa.contentTypeToString() @@ -1143,7 +1143,7 @@ public class MediaFocusControl implements PlayerFocusEnforcer { .record(); // AudioAttributes are currently ignored, to be used for zones / a11y - mEventLogger.log((new EventLogger.StringEvent( + mEventLogger.enqueue((new EventLogger.StringEvent( "abandonAudioFocus() from uid/pid " + Binder.getCallingUid() + "/" + Binder.getCallingPid() + " clientId=" + clientId)) diff --git a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java index 1af8c593f96b..74bfa80e4704 100644 --- a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java +++ b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java @@ -157,7 +157,7 @@ public final class PlaybackActivityMonitor if (index >= 0) { if (!disable) { if (DEBUG) { // hidden behind DEBUG, too noisy otherwise - sEventLogger.log(new EventLogger.StringEvent("unbanning uid:" + uid)); + sEventLogger.enqueue(new EventLogger.StringEvent("unbanning uid:" + uid)); } mBannedUids.remove(index); // nothing else to do, future playback requests from this uid are ok @@ -168,7 +168,7 @@ public final class PlaybackActivityMonitor checkBanPlayer(apc, uid); } if (DEBUG) { // hidden behind DEBUG, too noisy otherwise - sEventLogger.log(new EventLogger.StringEvent("banning uid:" + uid)); + sEventLogger.enqueue(new EventLogger.StringEvent("banning uid:" + uid)); } mBannedUids.add(new Integer(uid)); } // no else to handle, uid already not in list, so enabling again is no-op @@ -209,7 +209,7 @@ public final class PlaybackActivityMonitor updateAllowedCapturePolicy(apc, mAllowedCapturePolicies.get(uid)); } } - sEventLogger.log(new NewPlayerEvent(apc)); + sEventLogger.enqueue(new NewPlayerEvent(apc)); synchronized(mPlayerLock) { mPlayers.put(newPiid, apc); maybeMutePlayerAwaitingConnection(apc); @@ -229,7 +229,7 @@ public final class PlaybackActivityMonitor synchronized(mPlayerLock) { final AudioPlaybackConfiguration apc = mPlayers.get(new Integer(piid)); if (checkConfigurationCaller(piid, apc, binderUid)) { - sEventLogger.log(new AudioAttrEvent(piid, attr)); + sEventLogger.enqueue(new AudioAttrEvent(piid, attr)); change = apc.handleAudioAttributesEvent(attr); } else { Log.e(TAG, "Error updating audio attributes"); @@ -322,7 +322,7 @@ public final class PlaybackActivityMonitor return; } - sEventLogger.log(new PlayerEvent(piid, event, eventValue)); + sEventLogger.enqueue(new PlayerEvent(piid, event, eventValue)); if (event == AudioPlaybackConfiguration.PLAYER_UPDATE_PORT_ID) { mEventHandler.sendMessage( @@ -332,7 +332,7 @@ public final class PlaybackActivityMonitor for (Integer uidInteger: mBannedUids) { if (checkBanPlayer(apc, uidInteger.intValue())) { // player was banned, do not update its state - sEventLogger.log(new EventLogger.StringEvent( + sEventLogger.enqueue(new EventLogger.StringEvent( "not starting piid:" + piid + " ,is banned")); return; } @@ -412,7 +412,7 @@ public final class PlaybackActivityMonitor public void playerHasOpPlayAudio(int piid, boolean hasOpPlayAudio, int binderUid) { // no check on UID yet because this is only for logging at the moment - sEventLogger.log(new PlayerOpPlayAudioEvent(piid, hasOpPlayAudio, binderUid)); + sEventLogger.enqueue(new PlayerOpPlayAudioEvent(piid, hasOpPlayAudio, binderUid)); } public void releasePlayer(int piid, int binderUid) { @@ -421,7 +421,7 @@ public final class PlaybackActivityMonitor synchronized(mPlayerLock) { final AudioPlaybackConfiguration apc = mPlayers.get(new Integer(piid)); if (checkConfigurationCaller(piid, apc, binderUid)) { - sEventLogger.log(new EventLogger.StringEvent( + sEventLogger.enqueue(new EventLogger.StringEvent( "releasing player piid:" + piid)); mPlayers.remove(new Integer(piid)); mDuckingManager.removeReleased(apc); @@ -443,7 +443,7 @@ public final class PlaybackActivityMonitor } /*package*/ void onAudioServerDied() { - sEventLogger.log( + sEventLogger.enqueue( new EventLogger.StringEvent( "clear port id to piid map")); synchronized (mPlayerLock) { @@ -768,7 +768,7 @@ public final class PlaybackActivityMonitor } if (mute) { try { - sEventLogger.log((new EventLogger.StringEvent("call: muting piid:" + sEventLogger.enqueue((new EventLogger.StringEvent("call: muting piid:" + piid + " uid:" + apc.getClientUid())).printLog(TAG)); apc.getPlayerProxy().setVolume(0.0f); mMutedPlayers.add(new Integer(piid)); @@ -793,7 +793,7 @@ public final class PlaybackActivityMonitor final AudioPlaybackConfiguration apc = mPlayers.get(piid); if (apc != null) { try { - sEventLogger.log(new EventLogger.StringEvent("call: unmuting piid:" + sEventLogger.enqueue(new EventLogger.StringEvent("call: unmuting piid:" + piid).printLog(TAG)); apc.getPlayerProxy().setVolume(1.0f); } catch (Exception e) { @@ -1081,7 +1081,7 @@ public final class PlaybackActivityMonitor return; } try { - sEventLogger.log((new DuckEvent(apc, skipRamp)).printLog(TAG)); + sEventLogger.enqueue((new DuckEvent(apc, skipRamp)).printLog(TAG)); apc.getPlayerProxy().applyVolumeShaper( DUCK_VSHAPE, skipRamp ? PLAY_SKIP_RAMP : PLAY_CREATE_IF_NEEDED); @@ -1096,7 +1096,7 @@ public final class PlaybackActivityMonitor final AudioPlaybackConfiguration apc = players.get(piid); if (apc != null) { try { - sEventLogger.log((new EventLogger.StringEvent("unducking piid:" + sEventLogger.enqueue((new EventLogger.StringEvent("unducking piid:" + piid)).printLog(TAG)); apc.getPlayerProxy().applyVolumeShaper( DUCK_ID, @@ -1310,8 +1310,9 @@ public final class PlaybackActivityMonitor //========================================================================================== void muteAwaitConnection(@NonNull int[] usagesToMute, @NonNull AudioDeviceAttributes dev, long timeOutMs) { - sEventLogger.loglogi( - "muteAwaitConnection() dev:" + dev + " timeOutMs:" + timeOutMs, TAG); + sEventLogger.enqueueAndLog( + "muteAwaitConnection() dev:" + dev + " timeOutMs:" + timeOutMs, + EventLogger.Event.ALOGI, TAG); synchronized (mPlayerLock) { mutePlayersExpectingDevice(usagesToMute); // schedule timeout (remove previously scheduled first) @@ -1323,7 +1324,8 @@ public final class PlaybackActivityMonitor } void cancelMuteAwaitConnection(String source) { - sEventLogger.loglogi("cancelMuteAwaitConnection() from:" + source, TAG); + sEventLogger.enqueueAndLog("cancelMuteAwaitConnection() from:" + source, + EventLogger.Event.ALOGI, TAG); synchronized (mPlayerLock) { // cancel scheduled timeout, ignore device, only one expected device at a time mEventHandler.removeMessages(MSG_L_TIMEOUT_MUTE_AWAIT_CONNECTION); @@ -1346,7 +1348,7 @@ public final class PlaybackActivityMonitor @GuardedBy("mPlayerLock") private void mutePlayersExpectingDevice(@NonNull int[] usagesToMute) { - sEventLogger.log(new MuteAwaitConnectionEvent(usagesToMute)); + sEventLogger.enqueue(new MuteAwaitConnectionEvent(usagesToMute)); mMutedUsagesAwaitingConnection = usagesToMute; final Set<Integer> piidSet = mPlayers.keySet(); final Iterator<Integer> piidIterator = piidSet.iterator(); @@ -1369,7 +1371,7 @@ public final class PlaybackActivityMonitor for (int usage : mMutedUsagesAwaitingConnection) { if (usage == apc.getAudioAttributes().getUsage()) { try { - sEventLogger.log((new EventLogger.StringEvent( + sEventLogger.enqueue((new EventLogger.StringEvent( "awaiting connection: muting piid:" + apc.getPlayerInterfaceId() + " uid:" + apc.getClientUid())).printLog(TAG)); @@ -1394,7 +1396,7 @@ public final class PlaybackActivityMonitor continue; } try { - sEventLogger.log(new EventLogger.StringEvent( + sEventLogger.enqueue(new EventLogger.StringEvent( "unmuting piid:" + piid).printLog(TAG)); apc.getPlayerProxy().applyVolumeShaper(MUTE_AWAIT_CONNECTION_VSHAPE, VolumeShaper.Operation.REVERSE); @@ -1452,8 +1454,9 @@ public final class PlaybackActivityMonitor public void handleMessage(Message msg) { switch (msg.what) { case MSG_L_TIMEOUT_MUTE_AWAIT_CONNECTION: - sEventLogger.loglogi("Timeout for muting waiting for " - + (AudioDeviceAttributes) msg.obj + ", unmuting", TAG); + sEventLogger.enqueueAndLog("Timeout for muting waiting for " + + (AudioDeviceAttributes) msg.obj + ", unmuting", + EventLogger.Event.ALOGI, TAG); synchronized (mPlayerLock) { unmutePlayersExpectingDevice(); } @@ -1476,7 +1479,7 @@ public final class PlaybackActivityMonitor synchronized (mPlayerLock) { int piid = msg.arg1; - sEventLogger.log( + sEventLogger.enqueue( new PlayerEvent(piid, PLAYER_UPDATE_MUTED, eventValue)); final AudioPlaybackConfiguration apc = mPlayers.get(piid); diff --git a/services/core/java/com/android/server/audio/RecordingActivityMonitor.java b/services/core/java/com/android/server/audio/RecordingActivityMonitor.java index 2ba8882ae14f..652ea5228571 100644 --- a/services/core/java/com/android/server/audio/RecordingActivityMonitor.java +++ b/services/core/java/com/android/server/audio/RecordingActivityMonitor.java @@ -164,7 +164,7 @@ public final class RecordingActivityMonitor implements AudioSystem.AudioRecordin } if (MediaRecorder.isSystemOnlyAudioSource(source)) { // still want to log event, it just won't appear in recording configurations; - sEventLogger.log(new RecordingEvent(event, riid, config).printLog(TAG)); + sEventLogger.enqueue(new RecordingEvent(event, riid, config).printLog(TAG)); return; } dispatchCallbacks(updateSnapshot(event, riid, config)); @@ -204,7 +204,7 @@ public final class RecordingActivityMonitor implements AudioSystem.AudioRecordin ? AudioManager.RECORD_CONFIG_EVENT_STOP : AudioManager.RECORD_CONFIG_EVENT_NONE; if (riid == AudioManager.RECORD_RIID_INVALID || configEvent == AudioManager.RECORD_CONFIG_EVENT_NONE) { - sEventLogger.log(new RecordingEvent(event, riid, null).printLog(TAG)); + sEventLogger.enqueue(new RecordingEvent(event, riid, null).printLog(TAG)); return; } dispatchCallbacks(updateSnapshot(configEvent, riid, null)); @@ -301,7 +301,7 @@ public final class RecordingActivityMonitor implements AudioSystem.AudioRecordin if (!state.hasDeathHandler()) { if (state.isActiveConfiguration()) { configChanged = true; - sEventLogger.log(new RecordingEvent( + sEventLogger.enqueue(new RecordingEvent( AudioManager.RECORD_CONFIG_EVENT_RELEASE, state.getRiid(), state.getConfig())); } @@ -486,7 +486,7 @@ public final class RecordingActivityMonitor implements AudioSystem.AudioRecordin configChanged = false; } if (configChanged) { - sEventLogger.log(new RecordingEvent(event, riid, state.getConfig())); + sEventLogger.enqueue(new RecordingEvent(event, riid, state.getConfig())); configs = getActiveRecordingConfigurations(true /*isPrivileged*/); } } diff --git a/services/core/java/com/android/server/audio/SoundEffectsHelper.java b/services/core/java/com/android/server/audio/SoundEffectsHelper.java index 93eba50ac6dd..79b54ebfeb3c 100644 --- a/services/core/java/com/android/server/audio/SoundEffectsHelper.java +++ b/services/core/java/com/android/server/audio/SoundEffectsHelper.java @@ -164,7 +164,7 @@ class SoundEffectsHelper { } private void logEvent(String msg) { - mSfxLogger.log(new EventLogger.StringEvent(msg)); + mSfxLogger.enqueue(new EventLogger.StringEvent(msg)); } // All the methods below run on the worker thread diff --git a/services/core/java/com/android/server/audio/SpatializerHelper.java b/services/core/java/com/android/server/audio/SpatializerHelper.java index 1563d33d93f0..2b525f1fcf50 100644 --- a/services/core/java/com/android/server/audio/SpatializerHelper.java +++ b/services/core/java/com/android/server/audio/SpatializerHelper.java @@ -1708,11 +1708,11 @@ public class SpatializerHelper { private static void loglogi(String msg) { - AudioService.sSpatialLogger.loglogi(msg, TAG); + AudioService.sSpatialLogger.enqueueAndLog(msg, EventLogger.Event.ALOGI, TAG); } private static String logloge(String msg) { - AudioService.sSpatialLogger.loglog(msg, EventLogger.Event.ALOGE, TAG); + AudioService.sSpatialLogger.enqueueAndLog(msg, EventLogger.Event.ALOGE, TAG); return msg; } diff --git a/services/core/java/com/android/server/biometrics/sensors/SensorOverlays.java b/services/core/java/com/android/server/biometrics/sensors/SensorOverlays.java index aeb6b6e2a907..969a174f49c7 100644 --- a/services/core/java/com/android/server/biometrics/sensors/SensorOverlays.java +++ b/services/core/java/com/android/server/biometrics/sensors/SensorOverlays.java @@ -20,6 +20,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.hardware.biometrics.BiometricOverlayConstants; import android.hardware.fingerprint.ISidefpsController; +import android.hardware.fingerprint.IUdfpsOverlay; import android.hardware.fingerprint.IUdfpsOverlayController; import android.hardware.fingerprint.IUdfpsOverlayControllerCallback; import android.os.RemoteException; @@ -43,6 +44,7 @@ public final class SensorOverlays { @NonNull private final Optional<IUdfpsOverlayController> mUdfpsOverlayController; @NonNull private final Optional<ISidefpsController> mSidefpsController; + @NonNull private final Optional<IUdfpsOverlay> mUdfpsOverlay; /** * Create an overlay controller for each modality. @@ -52,9 +54,11 @@ public final class SensorOverlays { */ public SensorOverlays( @Nullable IUdfpsOverlayController udfpsOverlayController, - @Nullable ISidefpsController sidefpsController) { + @Nullable ISidefpsController sidefpsController, + @Nullable IUdfpsOverlay udfpsOverlay) { mUdfpsOverlayController = Optional.ofNullable(udfpsOverlayController); mSidefpsController = Optional.ofNullable(sidefpsController); + mUdfpsOverlay = Optional.ofNullable(udfpsOverlay); } /** @@ -90,6 +94,14 @@ public final class SensorOverlays { Slog.e(TAG, "Remote exception when showing the UDFPS overlay", e); } } + + if (mUdfpsOverlay.isPresent()) { + try { + mUdfpsOverlay.get().show(client.getRequestId(), sensorId, reason); + } catch (RemoteException e) { + Slog.e(TAG, "Remote exception when showing the new UDFPS overlay", e); + } + } } /** @@ -113,6 +125,14 @@ public final class SensorOverlays { Slog.e(TAG, "Remote exception when hiding the UDFPS overlay", e); } } + + if (mUdfpsOverlay.isPresent()) { + try { + mUdfpsOverlay.get().hide(sensorId); + } catch (RemoteException e) { + Slog.e(TAG, "Remote exception when hiding the new udfps overlay", e); + } + } } /** diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java index b0dc28ddce96..156e6bb503ec 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java @@ -52,6 +52,7 @@ import android.hardware.fingerprint.IFingerprintClientActiveCallback; import android.hardware.fingerprint.IFingerprintService; import android.hardware.fingerprint.IFingerprintServiceReceiver; import android.hardware.fingerprint.ISidefpsController; +import android.hardware.fingerprint.IUdfpsOverlay; import android.hardware.fingerprint.IUdfpsOverlayController; import android.os.Binder; import android.os.Build; @@ -874,6 +875,14 @@ public class FingerprintService extends SystemService { @android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL) @Override + public void setUdfpsOverlay(@NonNull IUdfpsOverlay controller) { + for (ServiceProvider provider : mRegistry.getProviders()) { + provider.setUdfpsOverlay(controller); + } + } + + @android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL) + @Override public void onPowerPressed() { for (ServiceProvider provider : mRegistry.getProviders()) { provider.onPowerPressed(); diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java index 0c29f5615b4c..05c2e2919a11 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java @@ -26,6 +26,7 @@ import android.hardware.fingerprint.FingerprintManager; import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; import android.hardware.fingerprint.IFingerprintServiceReceiver; import android.hardware.fingerprint.ISidefpsController; +import android.hardware.fingerprint.IUdfpsOverlay; import android.hardware.fingerprint.IUdfpsOverlayController; import android.os.IBinder; @@ -129,6 +130,12 @@ public interface ServiceProvider extends void setUdfpsOverlayController(@NonNull IUdfpsOverlayController controller); + /** + * Sets udfps overlay + * @param controller udfps overlay + */ + void setUdfpsOverlay(@NonNull IUdfpsOverlay controller); + void onPowerPressed(); /** diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java index 2e5663db57b5..7f1fb1cfc4bd 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java @@ -33,6 +33,7 @@ import android.hardware.biometrics.common.OperationContext; import android.hardware.biometrics.fingerprint.PointerContext; import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; import android.hardware.fingerprint.ISidefpsController; +import android.hardware.fingerprint.IUdfpsOverlay; import android.hardware.fingerprint.IUdfpsOverlayController; import android.os.Build; import android.os.Handler; @@ -118,6 +119,7 @@ class FingerprintAuthenticationClient extends AuthenticationClient<AidlSession> @NonNull LockoutCache lockoutCache, @Nullable IUdfpsOverlayController udfpsOverlayController, @Nullable ISidefpsController sidefpsController, + @Nullable IUdfpsOverlay udfpsOverlay, boolean allowBackgroundAuthentication, @NonNull FingerprintSensorPropertiesInternal sensorProps, @NonNull Handler handler, @@ -145,7 +147,8 @@ class FingerprintAuthenticationClient extends AuthenticationClient<AidlSession> false /* isKeyguardBypassEnabled */); setRequestId(requestId); mLockoutCache = lockoutCache; - mSensorOverlays = new SensorOverlays(udfpsOverlayController, sidefpsController); + mSensorOverlays = new SensorOverlays(udfpsOverlayController, + sidefpsController, udfpsOverlay); mSensorProps = sensorProps; mALSProbeCallback = getLogger().getAmbientLightProbe(false /* startWithClient */); mHandler = handler; @@ -248,8 +251,8 @@ class FingerprintAuthenticationClient extends AuthenticationClient<AidlSession> if (authenticated && mSensorProps.isAnySidefpsType()) { if (mHandler.hasMessages(MESSAGE_IGNORE_AUTH)) { Slog.i(TAG, "(sideFPS) Ignoring auth due to recent power press"); - onErrorInternal(BiometricConstants.BIOMETRIC_ERROR_POWER_PRESSED, 0, - true); + onErrorInternal(BiometricConstants.BIOMETRIC_ERROR_POWER_PRESSED, + 0, true); return; } delay = isKeyguard() ? mWaitForAuthKeyguard : mWaitForAuthBp; diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java index 0e89814c6ad2..52822347e96f 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java @@ -21,6 +21,7 @@ import android.annotation.Nullable; import android.content.Context; import android.hardware.biometrics.BiometricOverlayConstants; import android.hardware.biometrics.common.ICancellationSignal; +import android.hardware.fingerprint.IUdfpsOverlay; import android.hardware.fingerprint.IUdfpsOverlayController; import android.os.IBinder; import android.os.RemoteException; @@ -54,12 +55,15 @@ class FingerprintDetectClient extends AcquisitionClient<AidlSession> implements @NonNull ClientMonitorCallbackConverter listener, int userId, @NonNull String owner, int sensorId, @NonNull BiometricLogger biometricLogger, @NonNull BiometricContext biometricContext, - @Nullable IUdfpsOverlayController udfpsOverlayController, boolean isStrongBiometric) { + @Nullable IUdfpsOverlayController udfpsOverlayController, + @Nullable IUdfpsOverlay udfpsOverlay, + boolean isStrongBiometric) { super(context, lazyDaemon, token, listener, userId, owner, 0 /* cookie */, sensorId, true /* shouldVibrate */, biometricLogger, biometricContext); setRequestId(requestId); mIsStrongBiometric = isStrongBiometric; - mSensorOverlays = new SensorOverlays(udfpsOverlayController, null /* sideFpsController*/); + mSensorOverlays = new SensorOverlays(udfpsOverlayController, + null /* sideFpsController*/, udfpsOverlay); } @Override @@ -82,7 +86,8 @@ class FingerprintDetectClient extends AcquisitionClient<AidlSession> implements @Override protected void startHalOperation() { - mSensorOverlays.show(getSensorId(), BiometricOverlayConstants.REASON_AUTH_KEYGUARD, this); + mSensorOverlays.show(getSensorId(), BiometricOverlayConstants.REASON_AUTH_KEYGUARD, + this); try { mCancellationSignal = doDetectInteraction(); diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java index 612d90670888..7e5d39fdef1a 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java @@ -30,6 +30,7 @@ import android.hardware.fingerprint.Fingerprint; import android.hardware.fingerprint.FingerprintManager; import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; import android.hardware.fingerprint.ISidefpsController; +import android.hardware.fingerprint.IUdfpsOverlay; import android.hardware.fingerprint.IUdfpsOverlayController; import android.hardware.keymaster.HardwareAuthToken; import android.os.IBinder; @@ -86,6 +87,7 @@ class FingerprintEnrollClient extends EnrollClient<AidlSession> implements Udfps @NonNull FingerprintSensorPropertiesInternal sensorProps, @Nullable IUdfpsOverlayController udfpsOverlayController, @Nullable ISidefpsController sidefpsController, + @Nullable IUdfpsOverlay udfpsOverlay, int maxTemplatesPerUser, @FingerprintManager.EnrollReason int enrollReason) { // UDFPS haptics occur when an image is acquired (instead of when the result is known) super(context, lazyDaemon, token, listener, userId, hardwareAuthToken, owner, utils, @@ -93,7 +95,8 @@ class FingerprintEnrollClient extends EnrollClient<AidlSession> implements Udfps biometricContext); setRequestId(requestId); mSensorProps = sensorProps; - mSensorOverlays = new SensorOverlays(udfpsOverlayController, sidefpsController); + mSensorOverlays = new SensorOverlays(udfpsOverlayController, + sidefpsController, udfpsOverlay); mMaxTemplatesPerUser = maxTemplatesPerUser; mALSProbeCallback = getLogger().getAmbientLightProbe(true /* startWithClient */); @@ -162,7 +165,8 @@ class FingerprintEnrollClient extends EnrollClient<AidlSession> implements Udfps @Override protected void startHalOperation() { - mSensorOverlays.show(getSensorId(), getOverlayReasonFromEnrollReason(mEnrollReason), this); + mSensorOverlays.show(getSensorId(), getOverlayReasonFromEnrollReason(mEnrollReason), + this); BiometricNotificationUtils.cancelBadCalibrationNotification(getContext()); try { 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 628c16afed5c..a42ff9a8a2ba 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 @@ -40,6 +40,7 @@ import android.hardware.fingerprint.FingerprintManager; import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; import android.hardware.fingerprint.IFingerprintServiceReceiver; import android.hardware.fingerprint.ISidefpsController; +import android.hardware.fingerprint.IUdfpsOverlay; import android.hardware.fingerprint.IUdfpsOverlayController; import android.os.Binder; import android.os.Handler; @@ -108,6 +109,7 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi @Nullable private IFingerprint mDaemon; @Nullable private IUdfpsOverlayController mUdfpsOverlayController; @Nullable private ISidefpsController mSidefpsController; + @Nullable private IUdfpsOverlay mUdfpsOverlay; private final class BiometricTaskStackListener extends TaskStackListener { @Override @@ -383,7 +385,8 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi BiometricsProtoEnums.CLIENT_UNKNOWN), mBiometricContext, mSensors.get(sensorId).getSensorProperties(), - mUdfpsOverlayController, mSidefpsController, maxTemplatesPerUser, enrollReason); + mUdfpsOverlayController, mSidefpsController, mUdfpsOverlay, + maxTemplatesPerUser, enrollReason); scheduleForSensor(sensorId, client, new ClientMonitorCompositeCallback( mBiometricStateCallback, new ClientMonitorCallback() { @Override @@ -418,7 +421,7 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi opPackageName, sensorId, createLogger(BiometricsProtoEnums.ACTION_AUTHENTICATE, statsClient), mBiometricContext, - mUdfpsOverlayController, isStrongBiometric); + mUdfpsOverlayController, mUdfpsOverlay, isStrongBiometric); scheduleForSensor(sensorId, client, mBiometricStateCallback); }); @@ -439,10 +442,10 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi createLogger(BiometricsProtoEnums.ACTION_AUTHENTICATE, statsClient), mBiometricContext, isStrongBiometric, mTaskStackListener, mSensors.get(sensorId).getLockoutCache(), - mUdfpsOverlayController, mSidefpsController, allowBackgroundAuthentication, + mUdfpsOverlayController, mSidefpsController, mUdfpsOverlay, + allowBackgroundAuthentication, mSensors.get(sensorId).getSensorProperties(), mHandler, - Utils.getCurrentStrength(sensorId), - SystemClock.elapsedRealtimeClock()); + Utils.getCurrentStrength(sensorId), SystemClock.elapsedRealtimeClock()); scheduleForSensor(sensorId, client, mBiometricStateCallback); }); } @@ -649,6 +652,11 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi } @Override + public void setUdfpsOverlay(@NonNull IUdfpsOverlay controller) { + mUdfpsOverlay = controller; + } + + @Override public void dumpProtoState(int sensorId, @NonNull ProtoOutputStream proto, boolean clearSchedulerBuffer) { if (mSensors.contains(sensorId)) { diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java index 0e6df8e0df77..dbc96df9c458 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java @@ -38,6 +38,7 @@ import android.hardware.fingerprint.FingerprintSensorProperties; import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; import android.hardware.fingerprint.IFingerprintServiceReceiver; import android.hardware.fingerprint.ISidefpsController; +import android.hardware.fingerprint.IUdfpsOverlay; import android.hardware.fingerprint.IUdfpsOverlayController; import android.os.Handler; import android.os.IBinder; @@ -120,6 +121,7 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider @NonNull private final HalResultController mHalResultController; @Nullable private IUdfpsOverlayController mUdfpsOverlayController; @Nullable private ISidefpsController mSidefpsController; + @Nullable private IUdfpsOverlay mUdfpsOverlay; @NonNull private final BiometricContext mBiometricContext; // for requests that do not use biometric prompt @NonNull private final AtomicLong mRequestCounter = new AtomicLong(0); @@ -594,7 +596,7 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider createLogger(BiometricsProtoEnums.ACTION_ENROLL, BiometricsProtoEnums.CLIENT_UNKNOWN), mBiometricContext, - mUdfpsOverlayController, mSidefpsController, + mUdfpsOverlayController, mSidefpsController, mUdfpsOverlay, enrollReason); mScheduler.scheduleClientMonitor(client, new ClientMonitorCallback() { @Override @@ -640,7 +642,7 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider mLazyDaemon, token, id, listener, userId, opPackageName, mSensorProperties.sensorId, createLogger(BiometricsProtoEnums.ACTION_AUTHENTICATE, statsClient), - mBiometricContext, mUdfpsOverlayController, + mBiometricContext, mUdfpsOverlayController, mUdfpsOverlay, isStrongBiometric); mScheduler.scheduleClientMonitor(client, mBiometricStateCallback); }); @@ -664,7 +666,7 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider createLogger(BiometricsProtoEnums.ACTION_AUTHENTICATE, statsClient), mBiometricContext, isStrongBiometric, mTaskStackListener, mLockoutTracker, - mUdfpsOverlayController, mSidefpsController, + mUdfpsOverlayController, mSidefpsController, mUdfpsOverlay, allowBackgroundAuthentication, mSensorProperties); mScheduler.scheduleClientMonitor(client, mBiometricStateCallback); }); @@ -853,6 +855,11 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider } @Override + public void setUdfpsOverlay(@NonNull IUdfpsOverlay controller) { + mUdfpsOverlay = controller; + } + + @Override public void dumpProtoState(int sensorId, @NonNull ProtoOutputStream proto, boolean clearSchedulerBuffer) { final long sensorToken = proto.start(SensorServiceStateProto.SENSOR_STATES); diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java index 0d620fd3a9e4..56fa36ec20e2 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java @@ -26,6 +26,7 @@ import android.hardware.biometrics.BiometricFingerprintConstants; import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint; import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; import android.hardware.fingerprint.ISidefpsController; +import android.hardware.fingerprint.IUdfpsOverlay; import android.hardware.fingerprint.IUdfpsOverlayController; import android.os.IBinder; import android.os.RemoteException; @@ -76,15 +77,18 @@ class FingerprintAuthenticationClient extends AuthenticationClient<IBiometricsFi @NonNull LockoutFrameworkImpl lockoutTracker, @Nullable IUdfpsOverlayController udfpsOverlayController, @Nullable ISidefpsController sidefpsController, + @Nullable IUdfpsOverlay udfpsOverlay, boolean allowBackgroundAuthentication, @NonNull FingerprintSensorPropertiesInternal sensorProps) { super(context, lazyDaemon, token, listener, targetUserId, operationId, restricted, owner, cookie, requireConfirmation, sensorId, logger, biometricContext, - isStrongBiometric, taskStackListener, lockoutTracker, allowBackgroundAuthentication, - false /* shouldVibrate */, false /* isKeyguardBypassEnabled */); + isStrongBiometric, taskStackListener, lockoutTracker, + allowBackgroundAuthentication, false /* shouldVibrate */, + false /* isKeyguardBypassEnabled */); setRequestId(requestId); mLockoutFrameworkImpl = lockoutTracker; - mSensorOverlays = new SensorOverlays(udfpsOverlayController, sidefpsController); + mSensorOverlays = new SensorOverlays(udfpsOverlayController, + sidefpsController, udfpsOverlay); mSensorProps = sensorProps; mALSProbeCallback = getLogger().getAmbientLightProbe(false /* startWithClient */); } diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java index c2929d0f15b2..3e9b8ef7fab4 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java @@ -23,6 +23,7 @@ import android.hardware.biometrics.BiometricAuthenticator; import android.hardware.biometrics.BiometricFingerprintConstants; import android.hardware.biometrics.BiometricOverlayConstants; import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint; +import android.hardware.fingerprint.IUdfpsOverlay; import android.hardware.fingerprint.IUdfpsOverlayController; import android.os.IBinder; import android.os.RemoteException; @@ -62,11 +63,13 @@ class FingerprintDetectClient extends AcquisitionClient<IBiometricsFingerprint> @NonNull ClientMonitorCallbackConverter listener, int userId, @NonNull String owner, int sensorId, @NonNull BiometricLogger biometricLogger, @NonNull BiometricContext biometricContext, - @Nullable IUdfpsOverlayController udfpsOverlayController, boolean isStrongBiometric) { + @Nullable IUdfpsOverlayController udfpsOverlayController, + @Nullable IUdfpsOverlay udfpsOverlay, boolean isStrongBiometric) { super(context, lazyDaemon, token, listener, userId, owner, 0 /* cookie */, sensorId, true /* shouldVibrate */, biometricLogger, biometricContext); setRequestId(requestId); - mSensorOverlays = new SensorOverlays(udfpsOverlayController, null /* sideFpsController */); + mSensorOverlays = new SensorOverlays(udfpsOverlayController, + null /* sideFpsController */, udfpsOverlay); mIsStrongBiometric = isStrongBiometric; } @@ -92,7 +95,8 @@ class FingerprintDetectClient extends AcquisitionClient<IBiometricsFingerprint> @Override protected void startHalOperation() { - mSensorOverlays.show(getSensorId(), BiometricOverlayConstants.REASON_AUTH_KEYGUARD, this); + mSensorOverlays.show(getSensorId(), BiometricOverlayConstants.REASON_AUTH_KEYGUARD, + this); try { getFreshDaemon().authenticate(0 /* operationId */, getTargetUserId()); @@ -128,8 +132,8 @@ class FingerprintDetectClient extends AcquisitionClient<IBiometricsFingerprint> } @Override - public void onAuthenticated(BiometricAuthenticator.Identifier identifier, boolean authenticated, - ArrayList<Byte> hardwareAuthToken) { + public void onAuthenticated(BiometricAuthenticator.Identifier identifier, + boolean authenticated, ArrayList<Byte> hardwareAuthToken) { getLogger().logOnAuthenticated(getContext(), getOperationContext(), authenticated, false /* requireConfirmation */, getTargetUserId(), false /* isBiometricPrompt */); diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java index 5d9af5322c2e..3371cec32fde 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java @@ -26,6 +26,7 @@ import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint; import android.hardware.fingerprint.Fingerprint; import android.hardware.fingerprint.FingerprintManager; import android.hardware.fingerprint.ISidefpsController; +import android.hardware.fingerprint.IUdfpsOverlay; import android.hardware.fingerprint.IUdfpsOverlayController; import android.os.IBinder; import android.os.RemoteException; @@ -67,12 +68,14 @@ public class FingerprintEnrollClient extends EnrollClient<IBiometricsFingerprint @NonNull BiometricLogger biometricLogger, @NonNull BiometricContext biometricContext, @Nullable IUdfpsOverlayController udfpsOverlayController, @Nullable ISidefpsController sidefpsController, + @Nullable IUdfpsOverlay udfpsOverlay, @FingerprintManager.EnrollReason int enrollReason) { super(context, lazyDaemon, token, listener, userId, hardwareAuthToken, owner, utils, timeoutSec, sensorId, true /* shouldVibrate */, biometricLogger, biometricContext); setRequestId(requestId); - mSensorOverlays = new SensorOverlays(udfpsOverlayController, sidefpsController); + mSensorOverlays = new SensorOverlays(udfpsOverlayController, + sidefpsController, udfpsOverlay); mEnrollReason = enrollReason; if (enrollReason == FingerprintManager.ENROLL_FIND_SENSOR) { @@ -102,7 +105,8 @@ public class FingerprintEnrollClient extends EnrollClient<IBiometricsFingerprint @Override protected void startHalOperation() { - mSensorOverlays.show(getSensorId(), getOverlayReasonFromEnrollReason(mEnrollReason), this); + mSensorOverlays.show(getSensorId(), getOverlayReasonFromEnrollReason(mEnrollReason), + this); BiometricNotificationUtils.cancelBadCalibrationNotification(getContext()); try { diff --git a/services/core/java/com/android/server/infra/FrameworkResourcesServiceNameResolver.java b/services/core/java/com/android/server/infra/FrameworkResourcesServiceNameResolver.java index 5253d34a38f0..d4e8f27a7b34 100644 --- a/services/core/java/com/android/server/infra/FrameworkResourcesServiceNameResolver.java +++ b/services/core/java/com/android/server/infra/FrameworkResourcesServiceNameResolver.java @@ -19,28 +19,9 @@ import android.annotation.ArrayRes; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.StringRes; -import android.annotation.UserIdInt; -import android.app.AppGlobals; -import android.content.ComponentName; import android.content.Context; -import android.content.pm.PackageManager; -import android.content.pm.ServiceInfo; -import android.os.Handler; -import android.os.Looper; -import android.os.Message; -import android.os.SystemClock; -import android.text.TextUtils; -import android.util.Slog; -import android.util.SparseArray; -import android.util.SparseBooleanArray; -import android.util.TimeUtils; - -import com.android.internal.annotations.GuardedBy; import java.io.PrintWriter; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; /** * Gets the service name using a framework resources, temporarily changing the service if necessary @@ -48,259 +29,42 @@ import java.util.List; * * @hide */ -public final class FrameworkResourcesServiceNameResolver implements ServiceNameResolver { - - private static final String TAG = FrameworkResourcesServiceNameResolver.class.getSimpleName(); - - /** Handler message to {@link #resetTemporaryService(int)} */ - private static final int MSG_RESET_TEMPORARY_SERVICE = 0; +public final class FrameworkResourcesServiceNameResolver extends ServiceNameBaseResolver { - @NonNull - private final Context mContext; - @NonNull - private final Object mLock = new Object(); - @StringRes private final int mStringResourceId; @ArrayRes private final int mArrayResourceId; - private final boolean mIsMultiple; - /** - * Map of temporary service name list set by {@link #setTemporaryServices(int, String[], int)}, - * keyed by {@code userId}. - * - * <p>Typically used by Shell command and/or CTS tests to configure temporary services if - * mIsMultiple is true. - */ - @GuardedBy("mLock") - private final SparseArray<String[]> mTemporaryServiceNamesList = new SparseArray<>(); - /** - * Map of default services that have been disabled by - * {@link #setDefaultServiceEnabled(int, boolean)},keyed by {@code userId}. - * - * <p>Typically used by Shell command and/or CTS tests. - */ - @GuardedBy("mLock") - private final SparseBooleanArray mDefaultServicesDisabled = new SparseBooleanArray(); - @Nullable - private NameResolverListener mOnSetCallback; - /** - * When the temporary service will expire (and reset back to the default). - */ - @GuardedBy("mLock") - private long mTemporaryServiceExpiration; - - /** - * Handler used to reset the temporary service name. - */ - @GuardedBy("mLock") - private Handler mTemporaryHandler; public FrameworkResourcesServiceNameResolver(@NonNull Context context, @StringRes int resourceId) { - mContext = context; + super(context, false); mStringResourceId = resourceId; mArrayResourceId = -1; - mIsMultiple = false; } public FrameworkResourcesServiceNameResolver(@NonNull Context context, @ArrayRes int resourceId, boolean isMultiple) { + super(context, isMultiple); if (!isMultiple) { throw new UnsupportedOperationException("Please use " + "FrameworkResourcesServiceNameResolver(context, @StringRes int) constructor " + "if single service mode is requested."); } - mContext = context; mStringResourceId = -1; mArrayResourceId = resourceId; - mIsMultiple = true; - } - - @Override - public void setOnTemporaryServiceNameChangedCallback(@NonNull NameResolverListener callback) { - synchronized (mLock) { - this.mOnSetCallback = callback; - } - } - - @Override - public String getServiceName(@UserIdInt int userId) { - String[] serviceNames = getServiceNameList(userId); - return (serviceNames == null || serviceNames.length == 0) ? null : serviceNames[0]; - } - - @Override - public String getDefaultServiceName(@UserIdInt int userId) { - String[] serviceNames = getDefaultServiceNameList(userId); - return (serviceNames == null || serviceNames.length == 0) ? null : serviceNames[0]; - } - - /** - * Gets the default list of the service names for the given user. - * - * <p>Typically implemented by services which want to provide multiple backends. - */ - @Override - public String[] getServiceNameList(int userId) { - synchronized (mLock) { - String[] temporaryNames = mTemporaryServiceNamesList.get(userId); - if (temporaryNames != null) { - // Always log it, as it should only be used on CTS or during development - Slog.w(TAG, "getServiceName(): using temporary name " - + Arrays.toString(temporaryNames) + " for user " + userId); - return temporaryNames; - } - final boolean disabled = mDefaultServicesDisabled.get(userId); - if (disabled) { - // Always log it, as it should only be used on CTS or during development - Slog.w(TAG, "getServiceName(): temporary name not set and default disabled for " - + "user " + userId); - return null; - } - return getDefaultServiceNameList(userId); - - } - } - - /** - * Gets the default list of the service names for the given user. - * - * <p>Typically implemented by services which want to provide multiple backends. - */ - @Override - public String[] getDefaultServiceNameList(int userId) { - synchronized (mLock) { - if (mIsMultiple) { - String[] serviceNameList = mContext.getResources().getStringArray(mArrayResourceId); - // Filter out unimplemented services - // Initialize the validated array as null because we do not know the final size. - List<String> validatedServiceNameList = new ArrayList<>(); - try { - for (int i = 0; i < serviceNameList.length; i++) { - if (TextUtils.isEmpty(serviceNameList[i])) { - continue; - } - ComponentName serviceComponent = ComponentName.unflattenFromString( - serviceNameList[i]); - ServiceInfo serviceInfo = AppGlobals.getPackageManager().getServiceInfo( - serviceComponent, - PackageManager.MATCH_DIRECT_BOOT_AWARE - | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId); - if (serviceInfo != null) { - validatedServiceNameList.add(serviceNameList[i]); - } - } - } catch (Exception e) { - Slog.e(TAG, "Could not validate provided services.", e); - } - String[] validatedServiceNameArray = new String[validatedServiceNameList.size()]; - return validatedServiceNameList.toArray(validatedServiceNameArray); - } else { - final String name = mContext.getString(mStringResourceId); - return TextUtils.isEmpty(name) ? new String[0] : new String[]{name}; - } - } - } - - @Override - public boolean isConfiguredInMultipleMode() { - return mIsMultiple; - } - - @Override - public boolean isTemporary(@UserIdInt int userId) { - synchronized (mLock) { - return mTemporaryServiceNamesList.get(userId) != null; - } } @Override - public void setTemporaryService(@UserIdInt int userId, @NonNull String componentName, - int durationMs) { - setTemporaryServices(userId, new String[]{componentName}, durationMs); - } - - @Override - public void setTemporaryServices(int userId, @NonNull String[] componentNames, int durationMs) { - synchronized (mLock) { - mTemporaryServiceNamesList.put(userId, componentNames); - - if (mTemporaryHandler == null) { - mTemporaryHandler = new Handler(Looper.getMainLooper(), null, true) { - @Override - public void handleMessage(Message msg) { - if (msg.what == MSG_RESET_TEMPORARY_SERVICE) { - synchronized (mLock) { - resetTemporaryService(userId); - } - } else { - Slog.wtf(TAG, "invalid handler msg: " + msg); - } - } - }; - } else { - mTemporaryHandler.removeMessages(MSG_RESET_TEMPORARY_SERVICE); - } - mTemporaryServiceExpiration = SystemClock.elapsedRealtime() + durationMs; - mTemporaryHandler.sendEmptyMessageDelayed(MSG_RESET_TEMPORARY_SERVICE, durationMs); - for (int i = 0; i < componentNames.length; i++) { - notifyTemporaryServiceNameChangedLocked(userId, componentNames[i], - /* isTemporary= */ true); - } - } - } - - @Override - public void resetTemporaryService(@UserIdInt int userId) { - synchronized (mLock) { - Slog.i(TAG, "resetting temporary service for user " + userId + " from " - + Arrays.toString(mTemporaryServiceNamesList.get(userId))); - mTemporaryServiceNamesList.remove(userId); - if (mTemporaryHandler != null) { - mTemporaryHandler.removeMessages(MSG_RESET_TEMPORARY_SERVICE); - mTemporaryHandler = null; - } - notifyTemporaryServiceNameChangedLocked(userId, /* newTemporaryName= */ null, - /* isTemporary= */ false); - } - } - - @Override - public boolean setDefaultServiceEnabled(int userId, boolean enabled) { - synchronized (mLock) { - final boolean currentlyEnabled = isDefaultServiceEnabledLocked(userId); - if (currentlyEnabled == enabled) { - Slog.i(TAG, "setDefaultServiceEnabled(" + userId + "): already " + enabled); - return false; - } - if (enabled) { - Slog.i(TAG, "disabling default service for user " + userId); - mDefaultServicesDisabled.removeAt(userId); - } else { - Slog.i(TAG, "enabling default service for user " + userId); - mDefaultServicesDisabled.put(userId, true); - } - } - return true; + public String[] readServiceNameList(int userId) { + return mContext.getResources().getStringArray(mArrayResourceId); } + @Nullable @Override - public boolean isDefaultServiceEnabled(int userId) { - synchronized (mLock) { - return isDefaultServiceEnabledLocked(userId); - } + public String readServiceName(int userId) { + return mContext.getResources().getString(mStringResourceId); } - private boolean isDefaultServiceEnabledLocked(int userId) { - return !mDefaultServicesDisabled.get(userId); - } - - @Override - public String toString() { - synchronized (mLock) { - return "FrameworkResourcesServiceNamer[temps=" + mTemporaryServiceNamesList + "]"; - } - } // TODO(b/117779333): support proto @Override @@ -314,31 +78,4 @@ public final class FrameworkResourcesServiceNameResolver implements ServiceNameR pw.print(mDefaultServicesDisabled.size()); } } - - // TODO(b/117779333): support proto - @Override - public void dumpShort(@NonNull PrintWriter pw, @UserIdInt int userId) { - synchronized (mLock) { - final String[] temporaryNames = mTemporaryServiceNamesList.get(userId); - if (temporaryNames != null) { - pw.print("tmpName="); - pw.print(Arrays.toString(temporaryNames)); - final long ttl = mTemporaryServiceExpiration - SystemClock.elapsedRealtime(); - pw.print(" (expires in "); - TimeUtils.formatDuration(ttl, pw); - pw.print("), "); - } - pw.print("defaultName="); - pw.print(getDefaultServiceName(userId)); - final boolean disabled = mDefaultServicesDisabled.get(userId); - pw.println(disabled ? " (disabled)" : " (enabled)"); - } - } - - private void notifyTemporaryServiceNameChangedLocked(@UserIdInt int userId, - @Nullable String newTemporaryName, boolean isTemporary) { - if (mOnSetCallback != null) { - mOnSetCallback.onNameResolved(userId, newTemporaryName, isTemporary); - } - } } diff --git a/services/core/java/com/android/server/infra/SecureSettingsServiceNameResolver.java b/services/core/java/com/android/server/infra/SecureSettingsServiceNameResolver.java index cac7f53aad66..17d75e600c36 100644 --- a/services/core/java/com/android/server/infra/SecureSettingsServiceNameResolver.java +++ b/services/core/java/com/android/server/infra/SecureSettingsServiceNameResolver.java @@ -19,8 +19,11 @@ import android.annotation.NonNull; import android.annotation.UserIdInt; import android.content.Context; import android.provider.Settings; +import android.text.TextUtils; +import android.util.ArraySet; import java.io.PrintWriter; +import java.util.Set; /** * Gets the service name using a property from the {@link android.provider.Settings.Secure} @@ -28,21 +31,34 @@ import java.io.PrintWriter; * * @hide */ -public final class SecureSettingsServiceNameResolver implements ServiceNameResolver { +public final class SecureSettingsServiceNameResolver extends ServiceNameBaseResolver { + /** + * The delimiter to be used to parse the secure settings string. Services must make sure + * that this delimiter is used while adding component names to their secure setting property. + */ + private static final char COMPONENT_NAME_SEPARATOR = ':'; - private final @NonNull Context mContext; + private final TextUtils.SimpleStringSplitter mStringColonSplitter = + new TextUtils.SimpleStringSplitter(COMPONENT_NAME_SEPARATOR); @NonNull private final String mProperty; public SecureSettingsServiceNameResolver(@NonNull Context context, @NonNull String property) { - mContext = context; - mProperty = property; + this(context, property, /*isMultiple*/false); } - @Override - public String getDefaultServiceName(@UserIdInt int userId) { - return Settings.Secure.getStringForUser(mContext.getContentResolver(), mProperty, userId); + /** + * + * @param context the context required to retrieve the secure setting value + * @param property name of the secure setting key + * @param isMultiple true if the system service using this resolver needs to connect to + * multiple remote services, false otherwise + */ + public SecureSettingsServiceNameResolver(@NonNull Context context, @NonNull String property, + boolean isMultiple) { + super(context, isMultiple); + mProperty = property; } // TODO(b/117779333): support proto @@ -61,4 +77,34 @@ public final class SecureSettingsServiceNameResolver implements ServiceNameResol public String toString() { return "SecureSettingsServiceNameResolver[" + mProperty + "]"; } + + @Override + public String[] readServiceNameList(int userId) { + return parseColonDelimitedServiceNames( + Settings.Secure.getStringForUser( + mContext.getContentResolver(), mProperty, userId)); + } + + @Override + public String readServiceName(int userId) { + return Settings.Secure.getStringForUser( + mContext.getContentResolver(), mProperty, userId); + } + + private String[] parseColonDelimitedServiceNames(String serviceNames) { + final Set<String> delimitedServices = new ArraySet<>(); + if (!TextUtils.isEmpty(serviceNames)) { + final TextUtils.SimpleStringSplitter splitter = mStringColonSplitter; + splitter.setString(serviceNames); + while (splitter.hasNext()) { + final String str = splitter.next(); + if (TextUtils.isEmpty(str)) { + continue; + } + delimitedServices.add(str); + } + } + String[] delimitedServicesArray = new String[delimitedServices.size()]; + return delimitedServices.toArray(delimitedServicesArray); + } } diff --git a/services/core/java/com/android/server/infra/ServiceNameBaseResolver.java b/services/core/java/com/android/server/infra/ServiceNameBaseResolver.java new file mode 100644 index 000000000000..76ea05e36141 --- /dev/null +++ b/services/core/java/com/android/server/infra/ServiceNameBaseResolver.java @@ -0,0 +1,325 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.server.infra; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.UserIdInt; +import android.app.AppGlobals; +import android.content.ComponentName; +import android.content.Context; +import android.content.pm.PackageManager; +import android.content.pm.ServiceInfo; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.os.SystemClock; +import android.text.TextUtils; +import android.util.Slog; +import android.util.SparseArray; +import android.util.SparseBooleanArray; +import android.util.TimeUtils; + +import com.android.internal.annotations.GuardedBy; + +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * Gets the service name using a framework resources, temporarily changing the service if necessary + * (typically during CTS tests or service development). + * + * @hide + */ +public abstract class ServiceNameBaseResolver implements ServiceNameResolver { + + private static final String TAG = ServiceNameBaseResolver.class.getSimpleName(); + + /** Handler message to {@link #resetTemporaryService(int)} */ + private static final int MSG_RESET_TEMPORARY_SERVICE = 0; + + @NonNull + protected final Context mContext; + @NonNull + protected final Object mLock = new Object(); + + protected final boolean mIsMultiple; + /** + * Map of temporary service name list set by {@link #setTemporaryServices(int, String[], int)}, + * keyed by {@code userId}. + * + * <p>Typically used by Shell command and/or CTS tests to configure temporary services if + * mIsMultiple is true. + */ + @GuardedBy("mLock") + protected final SparseArray<String[]> mTemporaryServiceNamesList = new SparseArray<>(); + /** + * Map of default services that have been disabled by + * {@link #setDefaultServiceEnabled(int, boolean)},keyed by {@code userId}. + * + * <p>Typically used by Shell command and/or CTS tests. + */ + @GuardedBy("mLock") + protected final SparseBooleanArray mDefaultServicesDisabled = new SparseBooleanArray(); + @Nullable + private NameResolverListener mOnSetCallback; + /** + * When the temporary service will expire (and reset back to the default). + */ + @GuardedBy("mLock") + private long mTemporaryServiceExpiration; + + /** + * Handler used to reset the temporary service name. + */ + @GuardedBy("mLock") + private Handler mTemporaryHandler; + + protected ServiceNameBaseResolver(Context context, boolean isMultiple) { + mContext = context; + mIsMultiple = isMultiple; + } + + @Override + public void setOnTemporaryServiceNameChangedCallback(@NonNull NameResolverListener callback) { + synchronized (mLock) { + this.mOnSetCallback = callback; + } + } + + @Override + public String getServiceName(@UserIdInt int userId) { + String[] serviceNames = getServiceNameList(userId); + return (serviceNames == null || serviceNames.length == 0) ? null : serviceNames[0]; + } + + @Override + public String getDefaultServiceName(@UserIdInt int userId) { + String[] serviceNames = getDefaultServiceNameList(userId); + return (serviceNames == null || serviceNames.length == 0) ? null : serviceNames[0]; + } + + /** + * Gets the default list of the service names for the given user. + * + * <p>Typically implemented by services which want to provide multiple backends. + */ + @Override + public String[] getServiceNameList(int userId) { + synchronized (mLock) { + String[] temporaryNames = mTemporaryServiceNamesList.get(userId); + if (temporaryNames != null) { + // Always log it, as it should only be used on CTS or during development + Slog.w(TAG, "getServiceName(): using temporary name " + + Arrays.toString(temporaryNames) + " for user " + userId); + return temporaryNames; + } + final boolean disabled = mDefaultServicesDisabled.get(userId); + if (disabled) { + // Always log it, as it should only be used on CTS or during development + Slog.w(TAG, "getServiceName(): temporary name not set and default disabled for " + + "user " + userId); + return null; + } + return getDefaultServiceNameList(userId); + + } + } + + /** + * Base classes must override this to read from the desired config e.g. framework resource, + * secure settings etc. + */ + @Nullable + public abstract String[] readServiceNameList(int userId); + + /** + * Base classes must override this to read from the desired config e.g. framework resource, + * secure settings etc. + */ + @Nullable + public abstract String readServiceName(int userId); + + /** + * Gets the default list of the service names for the given user. + * + * <p>Typically implemented by services which want to provide multiple backends. + */ + @Override + public String[] getDefaultServiceNameList(int userId) { + synchronized (mLock) { + if (mIsMultiple) { + String[] serviceNameList = readServiceNameList(userId); + // Filter out unimplemented services + // Initialize the validated array as null because we do not know the final size. + List<String> validatedServiceNameList = new ArrayList<>(); + try { + for (int i = 0; i < serviceNameList.length; i++) { + if (TextUtils.isEmpty(serviceNameList[i])) { + continue; + } + ComponentName serviceComponent = ComponentName.unflattenFromString( + serviceNameList[i]); + ServiceInfo serviceInfo = AppGlobals.getPackageManager().getServiceInfo( + serviceComponent, + PackageManager.MATCH_DIRECT_BOOT_AWARE + | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId); + if (serviceInfo != null) { + validatedServiceNameList.add(serviceNameList[i]); + } + } + } catch (Exception e) { + Slog.e(TAG, "Could not validate provided services.", e); + } + String[] validatedServiceNameArray = new String[validatedServiceNameList.size()]; + return validatedServiceNameList.toArray(validatedServiceNameArray); + } else { + final String name = readServiceName(userId); + return TextUtils.isEmpty(name) ? new String[0] : new String[]{name}; + } + } + } + + @Override + public boolean isConfiguredInMultipleMode() { + return mIsMultiple; + } + + @Override + public boolean isTemporary(@UserIdInt int userId) { + synchronized (mLock) { + return mTemporaryServiceNamesList.get(userId) != null; + } + } + + @Override + public void setTemporaryService(@UserIdInt int userId, @NonNull String componentName, + int durationMs) { + setTemporaryServices(userId, new String[]{componentName}, durationMs); + } + + @Override + public void setTemporaryServices(int userId, @NonNull String[] componentNames, int durationMs) { + synchronized (mLock) { + mTemporaryServiceNamesList.put(userId, componentNames); + + if (mTemporaryHandler == null) { + mTemporaryHandler = new Handler(Looper.getMainLooper(), null, true) { + @Override + public void handleMessage(Message msg) { + if (msg.what == MSG_RESET_TEMPORARY_SERVICE) { + synchronized (mLock) { + resetTemporaryService(userId); + } + } else { + Slog.wtf(TAG, "invalid handler msg: " + msg); + } + } + }; + } else { + mTemporaryHandler.removeMessages(MSG_RESET_TEMPORARY_SERVICE); + } + mTemporaryServiceExpiration = SystemClock.elapsedRealtime() + durationMs; + mTemporaryHandler.sendEmptyMessageDelayed(MSG_RESET_TEMPORARY_SERVICE, durationMs); + for (int i = 0; i < componentNames.length; i++) { + notifyTemporaryServiceNameChangedLocked(userId, componentNames[i], + /* isTemporary= */ true); + } + } + } + + @Override + public void resetTemporaryService(@UserIdInt int userId) { + synchronized (mLock) { + Slog.i(TAG, "resetting temporary service for user " + userId + " from " + + Arrays.toString(mTemporaryServiceNamesList.get(userId))); + mTemporaryServiceNamesList.remove(userId); + if (mTemporaryHandler != null) { + mTemporaryHandler.removeMessages(MSG_RESET_TEMPORARY_SERVICE); + mTemporaryHandler = null; + } + notifyTemporaryServiceNameChangedLocked(userId, /* newTemporaryName= */ null, + /* isTemporary= */ false); + } + } + + @Override + public boolean setDefaultServiceEnabled(int userId, boolean enabled) { + synchronized (mLock) { + final boolean currentlyEnabled = isDefaultServiceEnabledLocked(userId); + if (currentlyEnabled == enabled) { + Slog.i(TAG, "setDefaultServiceEnabled(" + userId + "): already " + enabled); + return false; + } + if (enabled) { + Slog.i(TAG, "disabling default service for user " + userId); + mDefaultServicesDisabled.removeAt(userId); + } else { + Slog.i(TAG, "enabling default service for user " + userId); + mDefaultServicesDisabled.put(userId, true); + } + } + return true; + } + + @Override + public boolean isDefaultServiceEnabled(int userId) { + synchronized (mLock) { + return isDefaultServiceEnabledLocked(userId); + } + } + + @GuardedBy("mLock") + private boolean isDefaultServiceEnabledLocked(int userId) { + return !mDefaultServicesDisabled.get(userId); + } + + @Override + public String toString() { + synchronized (mLock) { + return "FrameworkResourcesServiceNamer[temps=" + mTemporaryServiceNamesList + "]"; + } + } + + // TODO(b/117779333): support proto + @Override + public void dumpShort(@NonNull PrintWriter pw, @UserIdInt int userId) { + synchronized (mLock) { + final String[] temporaryNames = mTemporaryServiceNamesList.get(userId); + if (temporaryNames != null) { + pw.print("tmpName="); + pw.print(Arrays.toString(temporaryNames)); + final long ttl = mTemporaryServiceExpiration - SystemClock.elapsedRealtime(); + pw.print(" (expires in "); + TimeUtils.formatDuration(ttl, pw); + pw.print("), "); + } + pw.print("defaultName="); + pw.print(getDefaultServiceName(userId)); + final boolean disabled = mDefaultServicesDisabled.get(userId); + pw.println(disabled ? " (disabled)" : " (enabled)"); + } + } + + private void notifyTemporaryServiceNameChangedLocked(@UserIdInt int userId, + @Nullable String newTemporaryName, boolean isTemporary) { + if (mOnSetCallback != null) { + mOnSetCallback.onNameResolved(userId, newTemporaryName, isTemporary); + } + } +} diff --git a/services/core/java/com/android/server/locales/LocaleManagerService.java b/services/core/java/com/android/server/locales/LocaleManagerService.java index 364f6db28f03..4ce03205fc1c 100644 --- a/services/core/java/com/android/server/locales/LocaleManagerService.java +++ b/services/core/java/com/android/server/locales/LocaleManagerService.java @@ -364,16 +364,19 @@ public class LocaleManagerService extends SystemService { // 1.) A normal, non-privileged app querying its own locale. // 2.) The installer of the given app querying locales of a package installed by said // installer. - // 3.) The current input method querying locales of another package. + // 3.) The current input method querying locales of the current foreground app. // 4.) A privileged system service querying locales of another package. // The least privileged case is a normal app performing a query, so check that first and get // locales if the package name is owned by the app. Next check if the calling app is the // installer of the given app and get locales. Finally check if the calling app is the - // current input method. If neither conditions matched, check if the caller has the - // necessary permission and fetch locales. + // current input method, and that app is querying locales of the current foreground app. If + // neither conditions matched, check if the caller has the necessary permission and fetch + // locales. if (!isPackageOwnedByCaller(appPackageName, userId) && !isCallerInstaller(appPackageName, userId) - && !isCallerFromCurrentInputMethod(userId)) { + && !(isCallerFromCurrentInputMethod(userId) + && mActivityManagerInternal.isAppForeground( + getPackageUid(appPackageName, userId)))) { enforceReadAppSpecificLocalesPermission(); } final long token = Binder.clearCallingIdentity(); diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java index f653b9381721..439e9bd2624e 100644 --- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java +++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java @@ -132,7 +132,7 @@ class MediaRouter2ServiceImpl { } } - mEventLogger.log(new EventLogger.StringEvent("mScreenOnOffReceiver", null)); + mEventLogger.enqueue(new EventLogger.StringEvent("mScreenOnOffReceiver", null)); } }; @@ -634,7 +634,7 @@ class MediaRouter2ServiceImpl { /* package */ void updateRunningUserAndProfiles(int newActiveUserId) { synchronized (mLock) { if (mCurrentActiveUserId != newActiveUserId) { - mEventLogger.log( + mEventLogger.enqueue( EventLogger.StringEvent.from("switchUser", "userId: %d", newActiveUserId)); @@ -705,7 +705,7 @@ class MediaRouter2ServiceImpl { obtainMessage(UserHandler::notifyRouterRegistered, userRecord.mHandler, routerRecord)); - mEventLogger.log(EventLogger.StringEvent.from("registerRouter2", + mEventLogger.enqueue(EventLogger.StringEvent.from("registerRouter2", "package: %s, uid: %d, pid: %d, router id: %d", packageName, uid, pid, routerRecord.mRouterId)); } @@ -718,7 +718,7 @@ class MediaRouter2ServiceImpl { return; } - mEventLogger.log( + mEventLogger.enqueue( EventLogger.StringEvent.from( "unregisterRouter2", "package: %s, router id: %d", @@ -744,7 +744,7 @@ class MediaRouter2ServiceImpl { return; } - mEventLogger.log(EventLogger.StringEvent.from( + mEventLogger.enqueue(EventLogger.StringEvent.from( "setDiscoveryRequestWithRouter2", "router id: %d, discovery request: %s", routerRecord.mRouterId, discoveryRequest.toString())); @@ -766,7 +766,7 @@ class MediaRouter2ServiceImpl { RouterRecord routerRecord = mAllRouterRecords.get(binder); if (routerRecord != null) { - mEventLogger.log(EventLogger.StringEvent.from( + mEventLogger.enqueue(EventLogger.StringEvent.from( "setRouteVolumeWithRouter2", "router id: %d, volume: %d", routerRecord.mRouterId, volume)); @@ -851,7 +851,7 @@ class MediaRouter2ServiceImpl { return; } - mEventLogger.log(EventLogger.StringEvent.from( + mEventLogger.enqueue(EventLogger.StringEvent.from( "selectRouteWithRouter2", "router id: %d, route: %s", routerRecord.mRouterId, route.getId())); @@ -871,7 +871,7 @@ class MediaRouter2ServiceImpl { return; } - mEventLogger.log(EventLogger.StringEvent.from( + mEventLogger.enqueue(EventLogger.StringEvent.from( "deselectRouteWithRouter2", "router id: %d, route: %s", routerRecord.mRouterId, route.getId())); @@ -891,7 +891,7 @@ class MediaRouter2ServiceImpl { return; } - mEventLogger.log(EventLogger.StringEvent.from( + mEventLogger.enqueue(EventLogger.StringEvent.from( "transferToRouteWithRouter2", "router id: %d, route: %s", routerRecord.mRouterId, route.getId())); @@ -921,7 +921,7 @@ class MediaRouter2ServiceImpl { return; } - mEventLogger.log(EventLogger.StringEvent.from( + mEventLogger.enqueue(EventLogger.StringEvent.from( "setSessionVolumeWithRouter2", "router id: %d, session: %s, volume: %d", routerRecord.mRouterId, uniqueSessionId, volume)); @@ -941,7 +941,7 @@ class MediaRouter2ServiceImpl { return; } - mEventLogger.log(EventLogger.StringEvent.from( + mEventLogger.enqueue(EventLogger.StringEvent.from( "releaseSessionWithRouter2", "router id: %d, session: %s", routerRecord.mRouterId, uniqueSessionId)); @@ -983,7 +983,7 @@ class MediaRouter2ServiceImpl { return; } - mEventLogger.log( + mEventLogger.enqueue( EventLogger.StringEvent.from("registerManager", "uid: %d, pid: %d, package: %s, userId: %d", uid, pid, packageName, userId)); @@ -1025,7 +1025,7 @@ class MediaRouter2ServiceImpl { } UserRecord userRecord = managerRecord.mUserRecord; - mEventLogger.log( + mEventLogger.enqueue( EventLogger.StringEvent.from( "unregisterManager", "package: %s, userId: %d, managerId: %d", @@ -1045,7 +1045,7 @@ class MediaRouter2ServiceImpl { return; } - mEventLogger.log( + mEventLogger.enqueue( EventLogger.StringEvent.from("startScan", "manager: %d", managerRecord.mManagerId)); @@ -1059,7 +1059,7 @@ class MediaRouter2ServiceImpl { return; } - mEventLogger.log( + mEventLogger.enqueue( EventLogger.StringEvent.from("stopScan", "manager: %d", managerRecord.mManagerId)); @@ -1076,7 +1076,7 @@ class MediaRouter2ServiceImpl { return; } - mEventLogger.log( + mEventLogger.enqueue( EventLogger.StringEvent.from("setRouteVolumeWithManager", "managerId: %d, routeId: %s, volume: %d", managerRecord.mManagerId, route.getId(), volume)); @@ -1096,7 +1096,7 @@ class MediaRouter2ServiceImpl { return; } - mEventLogger.log( + mEventLogger.enqueue( EventLogger.StringEvent.from("requestCreateSessionWithManager", "managerId: %d, routeId: %s", managerRecord.mManagerId, route.getId())); @@ -1146,7 +1146,7 @@ class MediaRouter2ServiceImpl { return; } - mEventLogger.log( + mEventLogger.enqueue( EventLogger.StringEvent.from("selectRouteWithManager", "managerId: %d, session: %s, routeId: %s", managerRecord.mManagerId, uniqueSessionId, route.getId())); @@ -1172,7 +1172,7 @@ class MediaRouter2ServiceImpl { return; } - mEventLogger.log( + mEventLogger.enqueue( EventLogger.StringEvent.from("deselectRouteWithManager", "managerId: %d, session: %s, routeId: %s", managerRecord.mManagerId, uniqueSessionId, route.getId())); @@ -1198,7 +1198,7 @@ class MediaRouter2ServiceImpl { return; } - mEventLogger.log( + mEventLogger.enqueue( EventLogger.StringEvent.from("transferToRouteWithManager", "managerId: %d, session: %s, routeId: %s", managerRecord.mManagerId, uniqueSessionId, route.getId())); @@ -1224,7 +1224,7 @@ class MediaRouter2ServiceImpl { return; } - mEventLogger.log( + mEventLogger.enqueue( EventLogger.StringEvent.from("setSessionVolumeWithManager", "managerId: %d, session: %s, volume: %d", managerRecord.mManagerId, uniqueSessionId, volume)); @@ -1245,7 +1245,7 @@ class MediaRouter2ServiceImpl { return; } - mEventLogger.log( + mEventLogger.enqueue( EventLogger.StringEvent.from("releaseSessionWithManager", "managerId: %d, session: %s", managerRecord.mManagerId, uniqueSessionId)); diff --git a/services/core/java/com/android/server/pm/BackgroundInstallControlService.java b/services/core/java/com/android/server/pm/BackgroundInstallControlService.java new file mode 100644 index 000000000000..df95f86d1e07 --- /dev/null +++ b/services/core/java/com/android/server/pm/BackgroundInstallControlService.java @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2022 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.pm; + +import android.annotation.NonNull; +import android.content.Context; +import android.content.pm.IBackgroundInstallControlService; +import android.content.pm.IPackageManager; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.content.pm.ParceledListSlice; +import android.os.IBinder; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.util.SparseArrayMap; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.server.SystemService; + +/** + * @hide + */ +public class BackgroundInstallControlService extends SystemService { + private static final String TAG = "BackgroundInstallControlService"; + + private final Context mContext; + private final BinderService mBinderService; + private final IPackageManager mIPackageManager; + + // User ID -> package name -> time diff + // The time diff between the last foreground activity installer and + // the "onPackageAdded" function call. + private final SparseArrayMap<String, Long> mBackgroundInstalledPackages = + new SparseArrayMap<>(); + + public BackgroundInstallControlService(@NonNull Context context) { + this(new InjectorImpl(context)); + } + + @VisibleForTesting + BackgroundInstallControlService(@NonNull Injector injector) { + super(injector.getContext()); + mContext = injector.getContext(); + mIPackageManager = injector.getIPackageManager(); + mBinderService = new BinderService(this); + } + + private static final class BinderService extends IBackgroundInstallControlService.Stub { + final BackgroundInstallControlService mService; + + BinderService(BackgroundInstallControlService service) { + mService = service; + } + + @Override + public ParceledListSlice<PackageInfo> getBackgroundInstalledPackages( + @PackageManager.PackageInfoFlagsBits long flags, int userId) { + ParceledListSlice<PackageInfo> packages; + try { + packages = mService.mIPackageManager.getInstalledPackages(flags, userId); + } catch (RemoteException e) { + throw new IllegalStateException("Package manager not available", e); + } + + // TODO(b/244216300): to enable the test the usage by BinaryTransparencyService, + // we currently comment out the actual implementation. + // The fake implementation is just to filter out the first app of the list. + // for (int i = 0, size = packages.getList().size(); i < size; i++) { + // String packageName = packages.getList().get(i).packageName; + // if (!mBackgroundInstalledPackages.contains(userId, packageName) { + // packages.getList().remove(i); + // } + // } + if (packages.getList().size() > 0) { + packages.getList().remove(0); + } + return packages; + } + } + + /** + * Called when the system service should publish a binder service using + * {@link #publishBinderService(String, IBinder).} + */ + @Override + public void onStart() { + publishBinderService(Context.BACKGROUND_INSTALL_CONTROL_SERVICE, mBinderService); + } + + /** + * Dependency injector for {@link #BackgroundInstallControlService)}. + */ + interface Injector { + Context getContext(); + + IPackageManager getIPackageManager(); + } + + private static final class InjectorImpl implements Injector { + private final Context mContext; + + InjectorImpl(Context context) { + mContext = context; + } + + @Override + public Context getContext() { + return mContext; + } + + @Override + public IPackageManager getIPackageManager() { + return IPackageManager.Stub.asInterface(ServiceManager.getService("package")); + } + } +} diff --git a/services/core/java/com/android/server/utils/EventLogger.java b/services/core/java/com/android/server/utils/EventLogger.java index 004312f06119..11766a3d70bd 100644 --- a/services/core/java/com/android/server/utils/EventLogger.java +++ b/services/core/java/com/android/server/utils/EventLogger.java @@ -43,7 +43,7 @@ public class EventLogger { /** * The maximum number of events to keep in {@code mEvents}. * - * <p>Calling {@link #log} when the size of {@link #mEvents} matches the threshold will + * <p>Calling {@link #enqueue} when the size of {@link #mEvents} matches the threshold will * cause the oldest event to be evicted. */ private final int mMemSize; @@ -60,7 +60,7 @@ public class EventLogger { } /** Enqueues {@code event} to be logged. */ - public synchronized void log(Event event) { + public synchronized void enqueue(Event event) { if (mEvents.size() >= mMemSize) { mEvents.removeLast(); } @@ -69,24 +69,14 @@ public class EventLogger { } /** - * Add a string-based event to the log, and print it to logcat as info. - * @param msg the message for the logs - * @param tag the logcat tag to use - */ - public synchronized void loglogi(String msg, String tag) { - final Event event = new StringEvent(msg); - log(event.printLog(tag)); - } - - /** - * Same as {@link #loglogi(String, String)} but specifying the logcat type + * Add a string-based event to the log, and print it to logcat with a specific severity. * @param msg the message for the logs * @param logType the type of logcat entry * @param tag the logcat tag to use */ - public synchronized void loglog(String msg, @Event.LogType int logType, String tag) { + public synchronized void enqueueAndLog(String msg, @Event.LogType int logType, String tag) { final Event event = new StringEvent(msg); - log(event.printLog(logType, tag)); + enqueue(event.printLog(logType, tag)); } /** Dumps events using {@link PrintWriter}. */ diff --git a/services/core/java/com/android/server/wm/ActivityStartInterceptor.java b/services/core/java/com/android/server/wm/ActivityStartInterceptor.java index 7d84bdf78056..d7c5e9373ad3 100644 --- a/services/core/java/com/android/server/wm/ActivityStartInterceptor.java +++ b/services/core/java/com/android/server/wm/ActivityStartInterceptor.java @@ -424,7 +424,7 @@ class ActivityStartInterceptor { try { harmfulAppWarning = mService.getPackageManager() .getHarmfulAppWarning(mAInfo.packageName, mUserId); - } catch (RemoteException ex) { + } catch (RemoteException | IllegalArgumentException ex) { return false; } diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index b74fedf3ff46..593e64828ffc 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -154,6 +154,7 @@ import com.android.server.os.SchedulingPolicyService; import com.android.server.people.PeopleService; import com.android.server.pm.ApexManager; import com.android.server.pm.ApexSystemServiceInfo; +import com.android.server.pm.BackgroundInstallControlService; import com.android.server.pm.CrossProfileAppsService; import com.android.server.pm.DataLoaderManagerService; import com.android.server.pm.DynamicCodeLoggingService; @@ -2469,6 +2470,10 @@ public final class SystemServer implements Dumpable { t.traceBegin("StartMediaMetricsManager"); mSystemServiceManager.startService(MediaMetricsManagerService.class); t.traceEnd(); + + t.traceBegin("StartBackgroundInstallControlService"); + mSystemServiceManager.startService(BackgroundInstallControlService.class); + t.traceEnd(); } t.traceBegin("StartMediaProjectionManager"); diff --git a/services/tests/mockingservicestests/src/com/android/server/job/JobConcurrencyManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/JobConcurrencyManagerTest.java index f46877e5a8c6..25473477e8b9 100644 --- a/services/tests/mockingservicestests/src/com/android/server/job/JobConcurrencyManagerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/job/JobConcurrencyManagerTest.java @@ -16,10 +16,19 @@ package com.android.server.job; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.server.job.JobConcurrencyManager.KEY_PKG_CONCURRENCY_LIMIT_EJ; import static com.android.server.job.JobConcurrencyManager.KEY_PKG_CONCURRENCY_LIMIT_REGULAR; +import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_BG; +import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_BGUSER; +import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_BGUSER_IMPORTANT; +import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_EJ; +import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_FGS; +import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_NONE; +import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_TOP; import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertFalse; @@ -47,15 +56,6 @@ import android.util.ArraySet; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; -import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; -import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_BG; -import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_BGUSER; -import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_BGUSER_IMPORTANT; -import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_EJ; -import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_FGS; -import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_NONE; -import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_TOP; - import com.android.internal.R; import com.android.internal.app.IBatteryStats; import com.android.server.LocalServices; @@ -73,6 +73,7 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoSession; import org.mockito.quality.Strictness; +import org.mockito.stubbing.Answer; import java.util.ArrayList; import java.util.List; @@ -124,6 +125,7 @@ public final class JobConcurrencyManagerTest { mMockingSession = mockitoSession() .initMocks(this) .mockStatic(AppGlobals.class) + .spyStatic(DeviceConfig.class) .strictness(Strictness.LENIENT) .startMocking(); final JobSchedulerService jobSchedulerService = mock(JobSchedulerService.class); @@ -134,6 +136,8 @@ public final class JobConcurrencyManagerTest { when(mContext.getResources()).thenReturn(mResources); doReturn(mContext).when(jobSchedulerService).getTestableContext(); mConfigBuilder = new DeviceConfig.Properties.Builder(DeviceConfig.NAMESPACE_JOB_SCHEDULER); + doAnswer((Answer<DeviceConfig.Properties>) invocationOnMock -> mConfigBuilder.build()) + .when(() -> DeviceConfig.getProperties(eq(DeviceConfig.NAMESPACE_JOB_SCHEDULER))); mPendingJobQueue = new PendingJobQueue(); doReturn(mPendingJobQueue).when(jobSchedulerService).getPendingJobQueue(); doReturn(mIPackageManager).when(AppGlobals::getPackageManager); @@ -595,7 +599,6 @@ public final class JobConcurrencyManagerTest { } private void updateDeviceConfig() throws Exception { - DeviceConfig.setProperties(mConfigBuilder.build()); mJobConcurrencyManager.updateConfigLocked(); } diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/SensorOverlaysTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/SensorOverlaysTest.java index 5012335b533f..21c9c753a062 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/SensorOverlaysTest.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/SensorOverlaysTest.java @@ -61,7 +61,7 @@ public class SensorOverlaysTest { @Test public void noopWhenBothNull() { - final SensorOverlays useless = new SensorOverlays(null, null); + final SensorOverlays useless = new SensorOverlays(null, null, null); useless.show(SENSOR_ID, 2, null); useless.hide(SENSOR_ID); } @@ -69,12 +69,12 @@ public class SensorOverlaysTest { @Test public void testProvidesUdfps() { final List<IUdfpsOverlayController> udfps = new ArrayList<>(); - SensorOverlays sensorOverlays = new SensorOverlays(null, mSidefpsController); + SensorOverlays sensorOverlays = new SensorOverlays(null, mSidefpsController, null); sensorOverlays.ifUdfps(udfps::add); assertThat(udfps).isEmpty(); - sensorOverlays = new SensorOverlays(mUdfpsOverlayController, mSidefpsController); + sensorOverlays = new SensorOverlays(mUdfpsOverlayController, mSidefpsController, null); sensorOverlays.ifUdfps(udfps::add); assertThat(udfps).containsExactly(mUdfpsOverlayController); } @@ -96,7 +96,7 @@ public class SensorOverlaysTest { private void testShow(IUdfpsOverlayController udfps, ISidefpsController sidefps) throws Exception { - final SensorOverlays sensorOverlays = new SensorOverlays(udfps, sidefps); + final SensorOverlays sensorOverlays = new SensorOverlays(udfps, sidefps, null); final int reason = BiometricOverlayConstants.REASON_UNKNOWN; sensorOverlays.show(SENSOR_ID, reason, mAcquisitionClient); @@ -126,7 +126,7 @@ public class SensorOverlaysTest { private void testHide(IUdfpsOverlayController udfps, ISidefpsController sidefps) throws Exception { - final SensorOverlays sensorOverlays = new SensorOverlays(udfps, sidefps); + final SensorOverlays sensorOverlays = new SensorOverlays(udfps, sidefps, null); sensorOverlays.hide(SENSOR_ID); if (udfps != null) { diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java index 1b5db0a35449..675f0e357aa8 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java @@ -645,7 +645,7 @@ public class FingerprintAuthenticationClientTest { 9 /* sensorId */, mBiometricLogger, mBiometricContext, true /* isStrongBiometric */, null /* taskStackListener */, mLockoutCache, - mUdfpsOverlayController, mSideFpsController, allowBackgroundAuthentication, + mUdfpsOverlayController, mSideFpsController, null, allowBackgroundAuthentication, mSensorProps, new Handler(mLooper.getLooper()), 0 /* biometricStrength */, mClock) { @Override diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClientTest.java index 93cbef19aca9..4579fc15f661 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClientTest.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClientTest.java @@ -118,6 +118,6 @@ public class FingerprintDetectClientTest { return new FingerprintDetectClient(mContext, () -> aidl, mToken, 6 /* requestId */, mClientMonitorCallbackConverter, 2 /* userId */, "a-test", 1 /* sensorId */, mBiometricLogger, mBiometricContext, - mUdfpsOverlayController, true /* isStrongBiometric */); + mUdfpsOverlayController, null, true /* isStrongBiometric */); } } diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java index 837b55397416..38b06c476174 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java @@ -28,7 +28,6 @@ import static org.mockito.Mockito.any; import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.never; import static org.mockito.Mockito.same; -import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -66,7 +65,6 @@ import org.mockito.Mock; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; -import java.util.ArrayList; import java.util.function.Consumer; @Presubmit @@ -292,6 +290,6 @@ public class FingerprintEnrollClientTest { mClientMonitorCallbackConverter, 0 /* userId */, HAT, "owner", mBiometricUtils, 8 /* sensorId */, mBiometricLogger, mBiometricContext, mSensorProps, mUdfpsOverlayController, - mSideFpsController, 6 /* maxTemplatesPerUser */, FingerprintManager.ENROLL_ENROLL); + mSideFpsController, null, 6 /* maxTemplatesPerUser */, FingerprintManager.ENROLL_ENROLL); } } diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java index 02bbe658f9b2..5fda3d6b36ab 100644 --- a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java @@ -891,4 +891,34 @@ public class VirtualDeviceManagerServiceTest { verify(mContext).startActivityAsUser(argThat(intent -> intent.filterEquals(blockedAppIntent)), any(), any()); } + + @Test + public void registerRunningAppsChangedListener_onRunningAppsChanged_listenersNotified() { + ArraySet<Integer> uids = new ArraySet<>(Arrays.asList(UID_1, UID_2)); + mDeviceImpl.onVirtualDisplayCreatedLocked( + mDeviceImpl.createWindowPolicyController(), DISPLAY_ID); + GenericWindowPolicyController gwpc = mDeviceImpl.getWindowPolicyControllersForTesting().get( + DISPLAY_ID); + + gwpc.onRunningAppsChanged(uids); + mDeviceImpl.onRunningAppsChanged(uids); + + assertThat(gwpc.getRunningAppsChangedListenersSizeForTesting()).isEqualTo(1); + verify(mRunningAppsChangedCallback).accept(new ArraySet<>(Arrays.asList(UID_1, UID_2))); + } + + @Test + public void noRunningAppsChangedListener_onRunningAppsChanged_doesNotThrowException() { + ArraySet<Integer> uids = new ArraySet<>(Arrays.asList(UID_1, UID_2)); + mDeviceImpl.onVirtualDisplayCreatedLocked( + mDeviceImpl.createWindowPolicyController(), DISPLAY_ID); + GenericWindowPolicyController gwpc = mDeviceImpl.getWindowPolicyControllersForTesting().get( + DISPLAY_ID); + mDeviceImpl.onVirtualDisplayRemovedLocked(DISPLAY_ID); + + // This call should not throw any exceptions. + gwpc.onRunningAppsChanged(uids); + + assertThat(gwpc.getRunningAppsChangedListenersSizeForTesting()).isEqualTo(0); + } } diff --git a/services/tests/servicestests/src/com/android/server/locales/LocaleManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/locales/LocaleManagerServiceTest.java index dbcd38c35958..dc9f90737713 100644 --- a/services/tests/servicestests/src/com/android/server/locales/LocaleManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/locales/LocaleManagerServiceTest.java @@ -229,6 +229,29 @@ public class LocaleManagerServiceTest { } } + @Test(expected = SecurityException.class) + public void testGetApplicationLocales_currentImeQueryNonForegroundAppLocales_fails() + throws Exception { + doReturn(DEFAULT_UID).when(mMockPackageManager) + .getPackageUidAsUser(anyString(), any(), anyInt()); + doReturn(new PackageConfig(/* nightMode = */ 0, DEFAULT_LOCALES)) + .when(mMockActivityTaskManager).getApplicationConfig(anyString(), anyInt()); + String imPkgName = getCurrentInputMethodPackageName(); + doReturn(Binder.getCallingUid()).when(mMockPackageManager) + .getPackageUidAsUser(eq(imPkgName), any(), anyInt()); + doReturn(false).when(mMockActivityManager).isAppForeground(anyInt()); + setUpFailingPermissionCheckFor(Manifest.permission.READ_APP_SPECIFIC_LOCALES); + + try { + mLocaleManagerService.getApplicationLocales(DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID); + fail("Expected SecurityException"); + } finally { + verify(mMockContext).enforceCallingOrSelfPermission( + eq(android.Manifest.permission.READ_APP_SPECIFIC_LOCALES), + anyString()); + } + } + @Test public void testGetApplicationLocales_appSpecificConfigAbsent_returnsEmptyList() throws Exception { @@ -307,7 +330,7 @@ public class LocaleManagerServiceTest { } @Test - public void testGetApplicationLocales_callerIsCurrentInputMethod_returnsLocales() + public void testGetApplicationLocales_currentImeQueryForegroundAppLocales_returnsLocales() throws Exception { doReturn(DEFAULT_UID).when(mMockPackageManager) .getPackageUidAsUser(anyString(), any(), anyInt()); @@ -316,6 +339,7 @@ public class LocaleManagerServiceTest { String imPkgName = getCurrentInputMethodPackageName(); doReturn(Binder.getCallingUid()).when(mMockPackageManager) .getPackageUidAsUser(eq(imPkgName), any(), anyInt()); + doReturn(true).when(mMockActivityManager).isAppForeground(anyInt()); LocaleList locales = mLocaleManagerService.getApplicationLocales( diff --git a/services/tests/servicestests/src/com/android/server/utils/EventLoggerTest.java b/services/tests/servicestests/src/com/android/server/utils/EventLoggerTest.java index 0b27f8734f23..4762696d7c61 100644 --- a/services/tests/servicestests/src/com/android/server/utils/EventLoggerTest.java +++ b/services/tests/servicestests/src/com/android/server/utils/EventLoggerTest.java @@ -125,7 +125,7 @@ public class EventLoggerTest { @Test public void testThatLoggingWorksAsExpected() { for (EventLogger.Event event: mEventsToInsert) { - mEventLogger.log(event); + mEventLogger.enqueue(event); } mEventLogger.dump(mTestPrintWriter); diff --git a/services/tests/uiservicestests/src/com/android/server/slice/SliceManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/slice/SliceManagerServiceTest.java index a917c57446a9..6ef5b0ecb2a0 100644 --- a/services/tests/uiservicestests/src/com/android/server/slice/SliceManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/slice/SliceManagerServiceTest.java @@ -51,6 +51,7 @@ import com.android.server.UiServiceTestCase; import org.junit.After; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; @@ -87,6 +88,7 @@ public class SliceManagerServiceTest extends UiServiceTestCase { LocalServices.removeServiceForTest(UsageStatsManagerInternal.class); } + @Ignore("b/253871109") @Test public void testAddPinCreatesPinned() throws RemoteException { grantSlicePermission(); @@ -97,6 +99,7 @@ public class SliceManagerServiceTest extends UiServiceTestCase { verify(mService, times(1)).createPinnedSlice(eq(maybeAddUserId(TEST_URI, 0)), anyString()); } + @Ignore("b/253871109") @Test public void testRemovePinDestroysPinned() throws RemoteException { grantSlicePermission(); @@ -109,6 +112,7 @@ public class SliceManagerServiceTest extends UiServiceTestCase { verify(mCreatedSliceState, never()).destroy(); } + @Ignore("b/253871109") @Test public void testCheckAutoGrantPermissions() throws RemoteException { String[] testPerms = new String[] { @@ -128,12 +132,14 @@ public class SliceManagerServiceTest extends UiServiceTestCase { verify(mContextSpy).checkPermission(eq("perm2"), eq(Process.myPid()), eq(Process.myUid())); } + @Ignore("b/253871109") @Test(expected = IllegalStateException.class) public void testNoPinThrow() throws Exception { grantSlicePermission(); mService.getPinnedSpecs(TEST_URI, "pkg"); } + @Ignore("b/253871109") @Test public void testGetPinnedSpecs() throws Exception { grantSlicePermission(); diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 9ecebf1a28f3..ff1b1c097d68 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -3323,15 +3323,14 @@ public class TelephonyManager { case NETWORK_TYPE_TD_SCDMA: return NETWORK_TYPE_BITMASK_TD_SCDMA; case NETWORK_TYPE_LTE: - return NETWORK_TYPE_BITMASK_LTE; case NETWORK_TYPE_LTE_CA: - return NETWORK_TYPE_BITMASK_LTE_CA; + return NETWORK_TYPE_BITMASK_LTE; case NETWORK_TYPE_NR: return NETWORK_TYPE_BITMASK_NR; case NETWORK_TYPE_IWLAN: return NETWORK_TYPE_BITMASK_IWLAN; case NETWORK_TYPE_IDEN: - return (1 << (NETWORK_TYPE_IDEN - 1)); + return NETWORK_TYPE_BITMASK_IDEN; default: return NETWORK_TYPE_BITMASK_UNKNOWN; } @@ -13911,7 +13910,8 @@ public class TelephonyManager { NETWORK_TYPE_BITMASK_LTE, NETWORK_TYPE_BITMASK_LTE_CA, NETWORK_TYPE_BITMASK_NR, - NETWORK_TYPE_BITMASK_IWLAN + NETWORK_TYPE_BITMASK_IWLAN, + NETWORK_TYPE_BITMASK_IDEN }) public @interface NetworkTypeBitMask {} @@ -13971,6 +13971,10 @@ public class TelephonyManager { */ public static final long NETWORK_TYPE_BITMASK_HSPA = (1 << (NETWORK_TYPE_HSPA -1)); /** + * network type bitmask indicating the support of radio tech iDen. + */ + public static final long NETWORK_TYPE_BITMASK_IDEN = (1 << (NETWORK_TYPE_IDEN - 1)); + /** * network type bitmask indicating the support of radio tech HSPAP. */ public static final long NETWORK_TYPE_BITMASK_HSPAP = (1 << (NETWORK_TYPE_HSPAP -1)); @@ -13988,12 +13992,13 @@ public class TelephonyManager { */ public static final long NETWORK_TYPE_BITMASK_LTE = (1 << (NETWORK_TYPE_LTE -1)); /** - * NOT USED; this bitmask is exposed accidentally, will be deprecated in U. + * NOT USED; this bitmask is exposed accidentally. * If used, will be converted to {@link #NETWORK_TYPE_BITMASK_LTE}. * network type bitmask indicating the support of radio tech LTE CA (carrier aggregation). * - * @see #NETWORK_TYPE_BITMASK_LTE + * @deprecated Please use {@link #NETWORK_TYPE_BITMASK_LTE} instead. */ + @Deprecated public static final long NETWORK_TYPE_BITMASK_LTE_CA = (1 << (NETWORK_TYPE_LTE_CA -1)); /** diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppAutoFocusHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppAutoFocusHelper.kt index 16753e63eb01..ca5b2afd0917 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppAutoFocusHelper.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppAutoFocusHelper.kt @@ -24,6 +24,8 @@ import androidx.test.uiautomator.By import androidx.test.uiautomator.Until import com.android.server.wm.flicker.testapp.ActivityOptions import com.android.server.wm.traces.common.ComponentNameMatcher +import com.android.server.wm.traces.common.Condition +import com.android.server.wm.traces.common.DeviceStateDump import com.android.server.wm.traces.parser.toFlickerComponent import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper import java.util.regex.Pattern @@ -47,9 +49,10 @@ constructor( wmHelper: WindowManagerStateHelper, expectedWindowName: String, action: String?, - stringExtras: Map<String, String> + stringExtras: Map<String, String>, + waitConditions: Array<Condition<DeviceStateDump>> ) { - super.launchViaIntent(wmHelper, expectedWindowName, action, stringExtras) + super.launchViaIntent(wmHelper, expectedWindowName, action, stringExtras, waitConditions) waitIMEShown(wmHelper) } |