Merge "Ensure that we always have a useable wallpaper token for animation" into main
diff --git a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__riscv64_CtsShimPriv_apk.asciipb b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__riscv64_CtsShimPriv_apk.asciipb
index e898091..e8e7ec9 100644
--- a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__riscv64_CtsShimPriv_apk.asciipb
+++ b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__riscv64_CtsShimPriv_apk.asciipb
@@ -1,6 +1,6 @@
drops {
android_build_drop {
- build_id: "9653376"
+ build_id: "11947186"
target: "CtsShim"
source_file: "aosp_riscv64/CtsShimPriv.apk"
}
@@ -8,7 +8,7 @@
version: ""
version_group: ""
git_project: "platform/frameworks/base"
- git_branch: "master"
+ git_branch: "main"
transform: TRANSFORM_NONE
transform_options {
}
diff --git a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__riscv64_CtsShim_apk.asciipb b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__riscv64_CtsShim_apk.asciipb
index 04092366..6113b6a 100644
--- a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__riscv64_CtsShim_apk.asciipb
+++ b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__riscv64_CtsShim_apk.asciipb
@@ -1,6 +1,6 @@
drops {
android_build_drop {
- build_id: "9653376"
+ build_id: "11947186"
target: "CtsShim"
source_file: "aosp_riscv64/CtsShim.apk"
}
@@ -8,7 +8,7 @@
version: ""
version_group: ""
git_project: "platform/frameworks/base"
- git_branch: "master"
+ git_branch: "main"
transform: TRANSFORM_NONE
transform_options {
}
diff --git a/apct-tests/perftests/core/Android.bp b/apct-tests/perftests/core/Android.bp
index e092499..65bc8cc 100644
--- a/apct-tests/perftests/core/Android.bp
+++ b/apct-tests/perftests/core/Android.bp
@@ -44,6 +44,7 @@
"apct-perftests-resources-manager-apps",
"apct-perftests-utils",
"collector-device-lib",
+ "conscrypt-test-support",
"compatibility-device-util-axt",
"junit",
"junit-params",
diff --git a/apct-tests/perftests/core/src/android/conscrypt/conscrypt/BufferType.java b/apct-tests/perftests/core/src/android/conscrypt/conscrypt/BufferType.java
new file mode 100644
index 0000000..bdc2a82
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/conscrypt/conscrypt/BufferType.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.conscrypt;
+
+import java.nio.ByteBuffer;
+import javax.net.ssl.SSLEngine;
+
+/**
+ * Enumeration that provides allocation of direct or heap buffers.
+ */
+@SuppressWarnings("unused")
+public enum BufferType {
+ HEAP {
+ @Override
+ ByteBuffer newBuffer(int size) {
+ return ByteBuffer.allocate(size);
+ }
+ },
+ DIRECT {
+ @Override
+ ByteBuffer newBuffer(int size) {
+ return ByteBuffer.allocateDirect(size);
+ }
+ };
+
+ abstract ByteBuffer newBuffer(int size);
+
+ ByteBuffer newApplicationBuffer(SSLEngine engine) {
+ return newBuffer(engine.getSession().getApplicationBufferSize());
+ }
+
+ ByteBuffer newPacketBuffer(SSLEngine engine) {
+ return newBuffer(engine.getSession().getPacketBufferSize());
+ }
+}
\ No newline at end of file
diff --git a/apct-tests/perftests/core/src/android/conscrypt/conscrypt/CipherEncryptPerfTest.java b/apct-tests/perftests/core/src/android/conscrypt/conscrypt/CipherEncryptPerfTest.java
new file mode 100644
index 0000000..c69ae39
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/conscrypt/conscrypt/CipherEncryptPerfTest.java
@@ -0,0 +1,228 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.conscrypt;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import androidx.test.filters.LargeTest;
+
+import org.conscrypt.TestUtils;
+
+import java.nio.ByteBuffer;
+import java.security.Key;
+import java.security.NoSuchAlgorithmException;
+import javax.crypto.Cipher;
+import javax.crypto.NoSuchPaddingException;
+
+import junitparams.JUnitParamsRunner;
+import junitparams.Parameters;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Benchmark for comparing cipher encrypt performance.
+ */
+@RunWith(JUnitParamsRunner.class)
+@LargeTest
+public final class CipherEncryptPerfTest {
+
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ public enum BufferType {
+ ARRAY,
+ HEAP_HEAP,
+ HEAP_DIRECT,
+ DIRECT_DIRECT,
+ DIRECT_HEAP
+ }
+
+ private enum MyCipherFactory implements CipherFactory {
+ JDK {
+ @Override
+ public Cipher newCipher(String transformation)
+ throws NoSuchPaddingException, NoSuchAlgorithmException {
+ return Cipher.getInstance(transformation);
+ }
+ },
+ CONSCRYPT {
+ @Override
+ public Cipher newCipher(String transformation)
+ throws NoSuchPaddingException, NoSuchAlgorithmException {
+ return Cipher.getInstance(transformation, TestUtils.getConscryptProvider());
+ }
+ };
+ }
+
+ private class Config {
+ BufferType b_bufferType;
+ CipherFactory c_provider;
+ Transformation a_tx;
+ Config(BufferType bufferType, CipherFactory cipherFactory, Transformation transformation) {
+ b_bufferType = bufferType;
+ c_provider = cipherFactory;
+ a_tx = transformation;
+ }
+ public BufferType bufferType() {
+ return b_bufferType;
+ }
+
+ public CipherFactory cipherFactory() {
+ return c_provider;
+ }
+
+ public Transformation transformation() {
+ return a_tx;
+ }
+ }
+
+ private Object[] getParams() {
+ return new Object[][] {
+ new Object[] {new Config(BufferType.ARRAY,
+ MyCipherFactory.CONSCRYPT,
+ Transformation.AES_CBC_PKCS5)},
+ new Object[] {new Config(BufferType.ARRAY,
+ MyCipherFactory.CONSCRYPT,
+ Transformation.AES_ECB_PKCS5)},
+ new Object[] {new Config(BufferType.ARRAY,
+ MyCipherFactory.CONSCRYPT,
+ Transformation.AES_GCM_NO)},
+ new Object[] {new Config(BufferType.ARRAY,
+ MyCipherFactory.CONSCRYPT,
+ Transformation.AES_GCM_SIV)},
+ };
+ }
+
+ private EncryptStrategy encryptStrategy;
+
+ @Test
+ @Parameters(method = "getParams")
+ public void encrypt(Config config) throws Exception {
+ switch (config.bufferType()) {
+ case ARRAY:
+ encryptStrategy = new ArrayStrategy(config);
+ break;
+ default:
+ encryptStrategy = new ByteBufferStrategy(config);
+ break;
+ }
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ encryptStrategy.encrypt();
+ }
+ }
+
+ private static abstract class EncryptStrategy {
+ private final Key key;
+ final Cipher cipher;
+ final int outputSize;
+
+ EncryptStrategy(Config config) throws Exception {
+ Transformation tx = config.transformation();
+ key = tx.newEncryptKey();
+ cipher = config.cipherFactory().newCipher(tx.toFormattedString());
+ initCipher();
+
+ int messageSize = messageSize(tx.toFormattedString());
+ outputSize = cipher.getOutputSize(messageSize);
+ }
+
+ final void initCipher() throws Exception {
+ cipher.init(Cipher.ENCRYPT_MODE, key);
+ }
+
+ final int messageSize(String transformation) throws Exception {
+ Cipher conscryptCipher = Cipher.getInstance(
+ transformation, TestUtils.getConscryptProvider());
+ conscryptCipher.init(Cipher.ENCRYPT_MODE, key);
+ return conscryptCipher.getBlockSize() > 0 ?
+ conscryptCipher.getBlockSize() : 128;
+ }
+
+ final byte[] newMessage() {
+ return TestUtils.newTextMessage(cipher.getBlockSize());
+ }
+
+ abstract int encrypt() throws Exception;
+ }
+
+ private static final class ArrayStrategy extends EncryptStrategy {
+ private final byte[] plainBytes;
+ private final byte[] cipherBytes;
+
+ ArrayStrategy(Config config) throws Exception {
+ super(config);
+
+ plainBytes = newMessage();
+ cipherBytes = new byte[outputSize];
+ }
+
+ @Override
+ int encrypt() throws Exception {
+ initCipher();
+ return cipher.doFinal(plainBytes, 0, plainBytes.length, cipherBytes, 0);
+ }
+ }
+
+ private static final class ByteBufferStrategy extends EncryptStrategy {
+ private final ByteBuffer input;
+ private final ByteBuffer output;
+
+ ByteBufferStrategy(Config config) throws Exception {
+ super(config);
+
+ switch (config.bufferType()) {
+ case HEAP_HEAP:
+ input = ByteBuffer.wrap(newMessage());
+ output = ByteBuffer.allocate(outputSize);
+ break;
+ case HEAP_DIRECT:
+ input = ByteBuffer.wrap(newMessage());
+ output = ByteBuffer.allocateDirect(outputSize);
+ break;
+ case DIRECT_DIRECT:
+ input = toDirect(newMessage());
+ output = ByteBuffer.allocateDirect(outputSize);
+ break;
+ case DIRECT_HEAP:
+ input = toDirect(newMessage());
+ output = ByteBuffer.allocate(outputSize);
+ break;
+ default: {
+ throw new IllegalStateException(
+ "Unexpected buffertype: " + config.bufferType());
+ }
+ }
+ }
+
+ @Override
+ int encrypt() throws Exception {
+ initCipher();
+ input.position(0);
+ output.clear();
+ return cipher.doFinal(input, output);
+ }
+
+ private static ByteBuffer toDirect(byte[] data) {
+ ByteBuffer buffer = ByteBuffer.allocateDirect(data.length);
+ buffer.put(data);
+ buffer.flip();
+ return buffer;
+ }
+ }
+}
\ No newline at end of file
diff --git a/apct-tests/perftests/core/src/android/conscrypt/conscrypt/CipherFactory.java b/apct-tests/perftests/core/src/android/conscrypt/conscrypt/CipherFactory.java
new file mode 100644
index 0000000..f8a3d5f
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/conscrypt/conscrypt/CipherFactory.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.conscrypt;
+
+import java.security.NoSuchAlgorithmException;
+import javax.crypto.Cipher;
+import javax.crypto.NoSuchPaddingException;
+
+/**
+ * Factory for {@link Cipher} instances.
+ */
+public interface CipherFactory {
+ Cipher newCipher(String transformation) throws NoSuchPaddingException, NoSuchAlgorithmException;
+}
\ No newline at end of file
diff --git a/apct-tests/perftests/core/src/android/conscrypt/conscrypt/ClientEndpoint.java b/apct-tests/perftests/core/src/android/conscrypt/conscrypt/ClientEndpoint.java
new file mode 100644
index 0000000..1a7258a
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/conscrypt/conscrypt/ClientEndpoint.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.conscrypt;
+
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.InetAddress;
+import java.net.SocketException;
+import java.nio.channels.ClosedChannelException;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+
+import org.conscrypt.ChannelType;
+
+/**
+ * Client-side endpoint. Provides basic services for sending/receiving messages from the client
+ * socket.
+ */
+final class ClientEndpoint {
+ private final SSLSocket socket;
+ private InputStream input;
+ private OutputStream output;
+
+ ClientEndpoint(SSLSocketFactory socketFactory, ChannelType channelType, int port,
+ String[] protocols, String[] ciphers) throws IOException {
+ socket = channelType.newClientSocket(socketFactory, InetAddress.getLoopbackAddress(), port);
+ socket.setEnabledProtocols(protocols);
+ socket.setEnabledCipherSuites(ciphers);
+ }
+
+ void start() {
+ try {
+ socket.startHandshake();
+ input = socket.getInputStream();
+ output = socket.getOutputStream();
+ } catch (IOException e) {
+ e.printStackTrace();
+ throw new RuntimeException(e);
+ }
+ }
+
+ void stop() {
+ try {
+ socket.close();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ int readMessage(byte[] buffer) {
+ try {
+ int totalBytesRead = 0;
+ while (totalBytesRead < buffer.length) {
+ int remaining = buffer.length - totalBytesRead;
+ int bytesRead = input.read(buffer, totalBytesRead, remaining);
+ if (bytesRead == -1) {
+ break;
+ }
+ totalBytesRead += bytesRead;
+ }
+ return totalBytesRead;
+ } catch (SSLException e) {
+ if (e.getCause() instanceof EOFException) {
+ return -1;
+ }
+ throw new RuntimeException(e);
+ } catch (ClosedChannelException e) {
+ // Thrown for channel-based sockets. Just treat like EOF.
+ return -1;
+ } catch (SocketException e) {
+ // The socket was broken. Just treat like EOF.
+ return -1;
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ void sendMessage(byte[] data) {
+ try {
+ output.write(data);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ void flush() {
+ try {
+ output.flush();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
\ No newline at end of file
diff --git a/apct-tests/perftests/core/src/android/conscrypt/conscrypt/ClientSocketPerfTest.java b/apct-tests/perftests/core/src/android/conscrypt/conscrypt/ClientSocketPerfTest.java
new file mode 100644
index 0000000..dd9f4eb
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/conscrypt/conscrypt/ClientSocketPerfTest.java
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.conscrypt;
+
+import org.conscrypt.ChannelType;
+import org.conscrypt.TestUtils;
+import static org.conscrypt.TestUtils.getCommonProtocolSuites;
+import static org.conscrypt.TestUtils.newTextMessage;
+import static org.junit.Assert.assertEquals;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import androidx.test.filters.LargeTest;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.SocketException;
+import java.security.NoSuchAlgorithmException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicLong;
+
+import javax.crypto.Cipher;
+import javax.crypto.NoSuchPaddingException;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import junitparams.JUnitParamsRunner;
+import junitparams.Parameters;
+import android.conscrypt.ServerEndpoint.MessageProcessor;
+
+/**
+ * Benchmark for comparing performance of server socket implementations.
+ */
+@RunWith(JUnitParamsRunner.class)
+@LargeTest
+public final class ClientSocketPerfTest {
+
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ /**
+ * Provider for the test configuration
+ */
+ private class Config {
+ EndpointFactory a_clientFactory;
+ EndpointFactory b_serverFactory;
+ int c_messageSize;
+ String d_cipher;
+ ChannelType e_channelType;
+ PerfTestProtocol f_protocol;
+ Config(EndpointFactory clientFactory,
+ EndpointFactory serverFactory,
+ int messageSize,
+ String cipher,
+ ChannelType channelType,
+ PerfTestProtocol protocol) {
+ a_clientFactory = clientFactory;
+ b_serverFactory = serverFactory;
+ c_messageSize = messageSize;
+ d_cipher = cipher;
+ e_channelType = channelType;
+ f_protocol = protocol;
+ }
+ public EndpointFactory clientFactory() {
+ return a_clientFactory;
+ }
+
+ public EndpointFactory serverFactory() {
+ return b_serverFactory;
+ }
+
+ public int messageSize() {
+ return c_messageSize;
+ }
+
+ public String cipher() {
+ return d_cipher;
+ }
+
+ public ChannelType channelType() {
+ return e_channelType;
+ }
+
+ public PerfTestProtocol protocol() {
+ return f_protocol;
+ }
+ }
+
+ private Object[] getParams() {
+ return new Object[][] {
+ new Object[] {new Config(
+ EndpointFactory.CONSCRYPT,
+ EndpointFactory.CONSCRYPT,
+ 64,
+ "AES128-GCM",
+ ChannelType.CHANNEL,
+ PerfTestProtocol.TLSv13)},
+ };
+ }
+
+
+ private ClientEndpoint client;
+ private ServerEndpoint server;
+ private byte[] message;
+ private ExecutorService executor;
+ private Future<?> sendingFuture;
+ private volatile boolean stopping;
+
+ private static final AtomicLong bytesCounter = new AtomicLong();
+ private AtomicBoolean recording = new AtomicBoolean();
+
+ private void setup(Config config) throws Exception {
+ message = newTextMessage(512);
+
+ // Always use the same server for consistency across the benchmarks.
+ server = config.serverFactory().newServer(
+ ChannelType.CHANNEL, config.messageSize(), config.protocol().getProtocols(),
+ ciphers(config));
+
+ server.setMessageProcessor(new ServerEndpoint.MessageProcessor() {
+ @Override
+ public void processMessage(byte[] inMessage, int numBytes, OutputStream os) {
+ if (recording.get()) {
+ // Server received a message, increment the count.
+ bytesCounter.addAndGet(numBytes);
+ }
+ }
+ });
+ Future<?> connectedFuture = server.start();
+
+ client = config.clientFactory().newClient(
+ config.channelType(), server.port(), config.protocol().getProtocols(), ciphers(config));
+ client.start();
+
+ // Wait for the initial connection to complete.
+ connectedFuture.get(5, TimeUnit.SECONDS);
+
+ executor = Executors.newSingleThreadExecutor();
+ sendingFuture = executor.submit(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ Thread thread = Thread.currentThread();
+ while (!stopping && !thread.isInterrupted()) {
+ client.sendMessage(message);
+ }
+ } finally {
+ client.flush();
+ }
+ }
+ });
+ }
+
+ void close() throws Exception {
+ stopping = true;
+
+ // Wait for the sending thread to stop.
+ sendingFuture.get(5, TimeUnit.SECONDS);
+
+ client.stop();
+ server.stop();
+ executor.shutdown();
+ executor.awaitTermination(5, TimeUnit.SECONDS);
+ }
+
+ /**
+ * Simple benchmark for the amount of time to send a given number of messages
+ */
+ @Test
+ @Parameters(method = "getParams")
+ public void time(Config config) throws Exception {
+ reset();
+ setup(config);
+ recording.set(true);
+
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ while (bytesCounter.get() < config.messageSize()) {
+ }
+ bytesCounter.set(0);
+ }
+ recording.set(false);
+ close();
+ }
+
+ void reset() {
+ stopping = false;
+ bytesCounter.set(0);
+ }
+
+ private String[] ciphers(Config config) {
+ return new String[] {config.cipher()};
+ }
+}
\ No newline at end of file
diff --git a/apct-tests/perftests/core/src/android/conscrypt/conscrypt/EndpointFactory.java b/apct-tests/perftests/core/src/android/conscrypt/conscrypt/EndpointFactory.java
new file mode 100644
index 0000000..0655f45
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/conscrypt/conscrypt/EndpointFactory.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.conscrypt;
+
+import org.conscrypt.ChannelType;
+import org.conscrypt.TestUtils;
+import java.io.IOException;
+import java.security.Provider;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLServerSocketFactory;
+import javax.net.ssl.SSLSocketFactory;
+
+/**
+ * Utility for creating test client and server instances.
+ */
+public enum EndpointFactory {
+ CONSCRYPT(newConscryptFactories(false)),
+ CONSCRYPT_ENGINE(newConscryptFactories(true));
+
+ private final Factories factories;
+
+ EndpointFactory(Factories factories) {
+ this.factories = factories;
+ }
+
+ public ClientEndpoint newClient(ChannelType channelType, int port, String[] protocols,
+ String[] ciphers) throws IOException {
+ return new ClientEndpoint(
+ factories.clientFactory, channelType, port, protocols, ciphers);
+ }
+
+ public ServerEndpoint newServer(ChannelType channelType, int messageSize,
+ String[] protocols, String[] ciphers) throws IOException {
+ return new ServerEndpoint(factories.serverFactory, factories.serverSocketFactory,
+ channelType, messageSize, protocols, ciphers);
+ }
+
+ private static final class Factories {
+ final SSLSocketFactory clientFactory;
+ final SSLSocketFactory serverFactory;
+ final SSLServerSocketFactory serverSocketFactory;
+
+ private Factories(SSLSocketFactory clientFactory, SSLSocketFactory serverFactory,
+ SSLServerSocketFactory serverSocketFactory) {
+ this.clientFactory = clientFactory;
+ this.serverFactory = serverFactory;
+ this.serverSocketFactory = serverSocketFactory;
+ }
+ }
+
+ private static Factories newConscryptFactories(boolean useEngineSocket) {
+ Provider provider = TestUtils.getConscryptProvider();
+ SSLContext clientContext = TestUtils.newClientSslContext(provider);
+ SSLContext serverContext = TestUtils.newServerSslContext(provider);
+ final SSLSocketFactory clientFactory = clientContext.getSocketFactory();
+ final SSLSocketFactory serverFactory = serverContext.getSocketFactory();
+ final SSLServerSocketFactory serverSocketFactory = serverContext.getServerSocketFactory();
+ TestUtils.setUseEngineSocket(clientFactory, useEngineSocket);
+ TestUtils.setUseEngineSocket(serverFactory, useEngineSocket);
+ TestUtils.setUseEngineSocket(serverSocketFactory, useEngineSocket);
+ return new Factories(clientFactory, serverFactory, serverSocketFactory);
+ }
+}
\ No newline at end of file
diff --git a/apct-tests/perftests/core/src/android/conscrypt/conscrypt/OWNERS b/apct-tests/perftests/core/src/android/conscrypt/conscrypt/OWNERS
new file mode 100644
index 0000000..7efabfd
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/conscrypt/conscrypt/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 24949
+include platform/libcore:/OWNERS
\ No newline at end of file
diff --git a/apct-tests/perftests/core/src/android/conscrypt/conscrypt/PerfTestProtocol.java b/apct-tests/perftests/core/src/android/conscrypt/conscrypt/PerfTestProtocol.java
new file mode 100644
index 0000000..4defe71
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/conscrypt/conscrypt/PerfTestProtocol.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.conscrypt;
+
+public enum PerfTestProtocol {
+
+ TLSv13("TLSv1.3"),
+ TLSv12("TLSv1.2");
+
+ private final String[] protocols;
+
+ PerfTestProtocol(String... protocols) {
+ this.protocols = protocols;
+ }
+
+ public String[] getProtocols() {
+ return protocols.clone();
+ }
+}
\ No newline at end of file
diff --git a/apct-tests/perftests/core/src/android/conscrypt/conscrypt/ServerEndpoint.java b/apct-tests/perftests/core/src/android/conscrypt/conscrypt/ServerEndpoint.java
new file mode 100644
index 0000000..3631c3f
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/conscrypt/conscrypt/ServerEndpoint.java
@@ -0,0 +1,199 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.conscrypt;
+
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.ServerSocket;
+import java.net.SocketException;
+import java.nio.channels.ClosedChannelException;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLServerSocketFactory;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+
+import org.conscrypt.ChannelType;
+
+/**
+ * A simple socket-based test server.
+ */
+final class ServerEndpoint {
+ /**
+ * A processor for receipt of a single message.
+ */
+ public interface MessageProcessor {
+ void processMessage(byte[] message, int numBytes, OutputStream os);
+ }
+
+ /**
+ * A {@link MessageProcessor} that simply echos back the received message to the client.
+ */
+ public static final class EchoProcessor implements MessageProcessor {
+ @Override
+ public void processMessage(byte[] message, int numBytes, OutputStream os) {
+ try {
+ os.write(message, 0, numBytes);
+ os.flush();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ private final ServerSocket serverSocket;
+ private final ChannelType channelType;
+ private final SSLSocketFactory socketFactory;
+ private final int messageSize;
+ private final String[] protocols;
+ private final String[] cipherSuites;
+ private final byte[] buffer;
+ private SSLSocket socket;
+ private ExecutorService executor;
+ private InputStream inputStream;
+ private OutputStream outputStream;
+ private volatile boolean stopping;
+ private volatile MessageProcessor messageProcessor = new EchoProcessor();
+ private volatile Future<?> processFuture;
+
+ ServerEndpoint(SSLSocketFactory socketFactory, SSLServerSocketFactory serverSocketFactory,
+ ChannelType channelType, int messageSize, String[] protocols,
+ String[] cipherSuites) throws IOException {
+ this.serverSocket = channelType.newServerSocket(serverSocketFactory);
+ this.socketFactory = socketFactory;
+ this.channelType = channelType;
+ this.messageSize = messageSize;
+ this.protocols = protocols;
+ this.cipherSuites = cipherSuites;
+ buffer = new byte[messageSize];
+ }
+
+ void setMessageProcessor(MessageProcessor messageProcessor) {
+ this.messageProcessor = messageProcessor;
+ }
+
+ Future<?> start() throws IOException {
+ executor = Executors.newSingleThreadExecutor();
+ return executor.submit(new AcceptTask());
+ }
+
+ void stop() {
+ try {
+ stopping = true;
+
+ if (socket != null) {
+ socket.close();
+ socket = null;
+ }
+
+ if (processFuture != null) {
+ processFuture.get(5, TimeUnit.SECONDS);
+ }
+
+ serverSocket.close();
+
+ if (executor != null) {
+ executor.shutdown();
+ executor.awaitTermination(5, TimeUnit.SECONDS);
+ executor = null;
+ }
+ } catch (IOException | InterruptedException | ExecutionException | TimeoutException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public int port() {
+ return serverSocket.getLocalPort();
+ }
+
+ private final class AcceptTask implements Runnable {
+ @Override
+ public void run() {
+ try {
+ if (stopping) {
+ return;
+ }
+ socket = channelType.accept(serverSocket, socketFactory);
+ socket.setEnabledProtocols(protocols);
+ socket.setEnabledCipherSuites(cipherSuites);
+
+ socket.startHandshake();
+
+ inputStream = socket.getInputStream();
+ outputStream = socket.getOutputStream();
+
+ if (stopping) {
+ return;
+ }
+ processFuture = executor.submit(new ProcessTask());
+ } catch (IOException e) {
+ e.printStackTrace();
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ private final class ProcessTask implements Runnable {
+ @Override
+ public void run() {
+ try {
+ Thread thread = Thread.currentThread();
+ while (!stopping && !thread.isInterrupted()) {
+ int bytesRead = readMessage();
+ if (!stopping && !thread.isInterrupted()) {
+ messageProcessor.processMessage(buffer, bytesRead, outputStream);
+ }
+ }
+ } catch (Throwable e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private int readMessage() throws IOException {
+ int totalBytesRead = 0;
+ while (!stopping && totalBytesRead < messageSize) {
+ try {
+ int remaining = messageSize - totalBytesRead;
+ int bytesRead = inputStream.read(buffer, totalBytesRead, remaining);
+ if (bytesRead == -1) {
+ break;
+ }
+ totalBytesRead += bytesRead;
+ } catch (SSLException e) {
+ if (e.getCause() instanceof EOFException) {
+ break;
+ }
+ throw e;
+ } catch (ClosedChannelException e) {
+ // Thrown for channel-based sockets. Just treat like EOF.
+ break;
+ } catch (SocketException e) {
+ // The socket was broken. Just treat like EOF.
+ break;
+ }
+ }
+ return totalBytesRead;
+ }
+ }
+}
\ No newline at end of file
diff --git a/apct-tests/perftests/core/src/android/conscrypt/conscrypt/ServerSocketPerfTest.java b/apct-tests/perftests/core/src/android/conscrypt/conscrypt/ServerSocketPerfTest.java
new file mode 100644
index 0000000..ba2a65a
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/conscrypt/conscrypt/ServerSocketPerfTest.java
@@ -0,0 +1,208 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.conscrypt;
+
+import org.conscrypt.ChannelType;
+import static org.conscrypt.TestUtils.getCommonProtocolSuites;
+import static org.conscrypt.TestUtils.newTextMessage;
+import static org.junit.Assert.assertEquals;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.SocketException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicLong;
+
+import android.conscrypt.ServerEndpoint.MessageProcessor;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import androidx.test.filters.LargeTest;
+
+import junitparams.JUnitParamsRunner;
+import junitparams.Parameters;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Benchmark for comparing performance of server socket implementations.
+ */
+@RunWith(JUnitParamsRunner.class)
+@LargeTest
+public final class ServerSocketPerfTest {
+
+ @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ /**
+ * Provider for the benchmark configuration
+ */
+ private class Config {
+ EndpointFactory a_clientFactory;
+ EndpointFactory b_serverFactory;
+ int c_messageSize;
+ String d_cipher;
+ ChannelType e_channelType;
+ Config(EndpointFactory clientFactory,
+ EndpointFactory serverFactory,
+ int messageSize,
+ String cipher,
+ ChannelType channelType) {
+ a_clientFactory = clientFactory;
+ b_serverFactory = serverFactory;
+ c_messageSize = messageSize;
+ d_cipher = cipher;
+ e_channelType = channelType;
+ }
+ public EndpointFactory clientFactory() {
+ return a_clientFactory;
+ }
+
+ public EndpointFactory serverFactory() {
+ return b_serverFactory;
+ }
+
+ public int messageSize() {
+ return c_messageSize;
+ }
+
+ public String cipher() {
+ return d_cipher;
+ }
+
+ public ChannelType channelType() {
+ return e_channelType;
+ }
+ }
+
+ private Object[] getParams() {
+ return new Object[][] {
+ new Object[] {new Config(
+ EndpointFactory.CONSCRYPT,
+ EndpointFactory.CONSCRYPT,
+ 64,
+ "AES128-GCM",
+ ChannelType.CHANNEL)},
+ };
+ }
+
+ private ClientEndpoint client;
+ private ServerEndpoint server;
+ private ExecutorService executor;
+ private Future<?> receivingFuture;
+ private volatile boolean stopping;
+ private static final AtomicLong bytesCounter = new AtomicLong();
+ private AtomicBoolean recording = new AtomicBoolean();
+
+ private void setup(final Config config) throws Exception {
+ recording.set(false);
+
+ byte[] message = newTextMessage(config.messageSize());
+
+ final ChannelType channelType = config.channelType();
+
+ server = config.serverFactory().newServer(
+ channelType, config.messageSize(), getCommonProtocolSuites(), ciphers(config));
+ server.setMessageProcessor(new MessageProcessor() {
+ @Override
+ public void processMessage(byte[] inMessage, int numBytes, OutputStream os) {
+ try {
+ try {
+ while (!stopping) {
+ os.write(inMessage, 0, numBytes);
+ }
+ } finally {
+ os.flush();
+ }
+ } catch (SocketException e) {
+ // Just ignore.
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ });
+
+ Future<?> connectedFuture = server.start();
+
+ // Always use the same client for consistency across the benchmarks.
+ client = config.clientFactory().newClient(
+ ChannelType.CHANNEL, server.port(), getCommonProtocolSuites(), ciphers(config));
+ client.start();
+
+ // Wait for the initial connection to complete.
+ connectedFuture.get(5, TimeUnit.SECONDS);
+
+ // Start the server-side streaming by sending a message to the server.
+ client.sendMessage(message);
+ client.flush();
+
+ executor = Executors.newSingleThreadExecutor();
+ receivingFuture = executor.submit(new Runnable() {
+ @Override
+ public void run() {
+ Thread thread = Thread.currentThread();
+ byte[] buffer = new byte[config.messageSize()];
+ while (!stopping && !thread.isInterrupted()) {
+ int numBytes = client.readMessage(buffer);
+ if (numBytes < 0) {
+ return;
+ }
+ assertEquals(config.messageSize(), numBytes);
+
+ // Increment the message counter if we're recording.
+ if (recording.get()) {
+ bytesCounter.addAndGet(numBytes);
+ }
+ }
+ }
+ });
+ }
+
+ void close() throws Exception {
+ stopping = true;
+ // Stop and wait for sending to complete.
+ server.stop();
+ client.stop();
+ executor.shutdown();
+ receivingFuture.get(5, TimeUnit.SECONDS);
+ executor.awaitTermination(5, TimeUnit.SECONDS);
+ }
+
+ @Test
+ @Parameters(method = "getParams")
+ public void throughput(Config config) throws Exception {
+ setup(config);
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ recording.set(true);
+ while (bytesCounter.get() < config.messageSize()) {
+ }
+ bytesCounter.set(0);
+ recording.set(false);
+ }
+ close();
+ }
+
+ private String[] ciphers(Config config) {
+ return new String[] {config.cipher()};
+ }
+}
\ No newline at end of file
diff --git a/apct-tests/perftests/core/src/android/conscrypt/conscrypt/Transformation.java b/apct-tests/perftests/core/src/android/conscrypt/conscrypt/Transformation.java
new file mode 100644
index 0000000..78fe732
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/conscrypt/conscrypt/Transformation.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.conscrypt;
+
+import java.security.Key;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.NoSuchAlgorithmException;
+import javax.crypto.KeyGenerator;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+
+/**
+ * Supported cipher transformations.
+ */
+@SuppressWarnings({"ImmutableEnumChecker", "unused"})
+public enum Transformation {
+ AES_CBC_PKCS5("AES", "CBC", "PKCS5Padding", new AesKeyGen()),
+ AES_ECB_PKCS5("AES", "ECB", "PKCS5Padding", new AesKeyGen()),
+ AES_GCM_NO("AES", "GCM", "NoPadding", new AesKeyGen()),
+ AES_GCM_SIV("AES", "GCM_SIV", "NoPadding", new AesKeyGen()),
+ RSA_ECB_PKCS1("RSA", "ECB", "PKCS1Padding", new RsaKeyGen());
+
+ Transformation(String algorithm, String mode, String padding, KeyGen keyGen) {
+ this.algorithm = algorithm;
+ this.mode = mode;
+ this.padding = padding;
+ this.keyGen = keyGen;
+ }
+
+ final String algorithm;
+ final String mode;
+ final String padding;
+ final KeyGen keyGen;
+
+ String toFormattedString() {
+ return algorithm + "/" + mode + "/" + padding;
+ }
+
+ Key newEncryptKey() {
+ return keyGen.newEncryptKey();
+ }
+
+ private interface KeyGen { Key newEncryptKey(); }
+
+ private static final class RsaKeyGen implements KeyGen {
+ @Override
+ public Key newEncryptKey() {
+ try {
+ // Use Bouncy castle
+ KeyPairGenerator generator =
+ KeyPairGenerator.getInstance("RSA", new BouncyCastleProvider());
+ generator.initialize(2048);
+ KeyPair pair = generator.generateKeyPair();
+ return pair.getPublic();
+ } catch (NoSuchAlgorithmException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ private static final class AesKeyGen implements KeyGen {
+ @Override
+ public Key newEncryptKey() {
+ try {
+ // Just use the JDK's provider.
+ KeyGenerator keyGen = KeyGenerator.getInstance("AES");
+ keyGen.init(256);
+ return keyGen.generateKey();
+ } catch (NoSuchAlgorithmException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/apct-tests/perftests/windowmanager/src/android/wm/RelayoutPerfTest.java b/apct-tests/perftests/windowmanager/src/android/wm/RelayoutPerfTest.java
index d80d3c8..b955032 100644
--- a/apct-tests/perftests/windowmanager/src/android/wm/RelayoutPerfTest.java
+++ b/apct-tests/perftests/windowmanager/src/android/wm/RelayoutPerfTest.java
@@ -18,11 +18,8 @@
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
-import static com.android.window.flags.Flags.windowSessionRelayoutInfo;
-
import android.app.Activity;
import android.content.Context;
-import android.os.Bundle;
import android.os.RemoteException;
import android.perftests.utils.BenchmarkState;
import android.perftests.utils.PerfStatusReporter;
@@ -131,7 +128,6 @@
final MergedConfiguration mOutMergedConfiguration = new MergedConfiguration();
final InsetsState mOutInsetsState = new InsetsState();
final InsetsSourceControl.Array mOutControls = new InsetsSourceControl.Array();
- final Bundle mOutBundle = windowSessionRelayoutInfo() ? null : new Bundle();
final WindowRelayoutResult mOutRelayoutResult;
final IWindow mWindow;
final View mView;
@@ -152,26 +148,16 @@
mHeight = mView.getMeasuredHeight();
mOutSurfaceControl = mView.getViewRootImpl().getSurfaceControl();
mViewVisibility = visibilitySupplier;
- mOutRelayoutResult = windowSessionRelayoutInfo()
- ? new WindowRelayoutResult(mOutFrames, mOutMergedConfiguration,
- mOutSurfaceControl, mOutInsetsState, mOutControls)
- : null;
+ mOutRelayoutResult = new WindowRelayoutResult(mOutFrames, mOutMergedConfiguration,
+ mOutSurfaceControl, mOutInsetsState, mOutControls);
}
void runBenchmark(BenchmarkState state) throws RemoteException {
final IWindowSession session = WindowManagerGlobal.getWindowSession();
while (state.keepRunning()) {
mRelayoutSeq++;
- if (windowSessionRelayoutInfo()) {
- session.relayout(mWindow, mParams, mWidth, mHeight,
- mViewVisibility.getAsInt(), mFlags, mRelayoutSeq, 0 /* lastSyncSeqId */,
- mOutRelayoutResult);
- } else {
- session.relayoutLegacy(mWindow, mParams, mWidth, mHeight,
- mViewVisibility.getAsInt(), mFlags, mRelayoutSeq, 0 /* lastSyncSeqId */,
- mOutFrames, mOutMergedConfiguration, mOutSurfaceControl,
- mOutInsetsState, mOutControls, mOutBundle);
- }
+ session.relayout(mWindow, mParams, mWidth, mHeight, mViewVisibility.getAsInt(),
+ mFlags, mRelayoutSeq, 0 /* lastSyncSeqId */, mOutRelayoutResult);
}
}
}
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
index b982d12..dfa7206 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
@@ -4925,7 +4925,6 @@
sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
sdFilter.addAction(Intent.ACTION_USER_STOPPED);
if (mStartUserBeforeScheduledAlarms) {
- sdFilter.addAction(Intent.ACTION_LOCKED_BOOT_COMPLETED);
sdFilter.addAction(Intent.ACTION_USER_REMOVED);
}
sdFilter.addAction(Intent.ACTION_UID_REMOVED);
@@ -4958,14 +4957,6 @@
mTemporaryQuotaReserve.removeForUser(userHandle);
}
return;
- case Intent.ACTION_LOCKED_BOOT_COMPLETED:
- final int handle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
- if (handle >= 0) {
- if (mStartUserBeforeScheduledAlarms) {
- mUserWakeupStore.onUserStarted(handle);
- }
- }
- return;
case Intent.ACTION_USER_REMOVED:
final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
if (user >= 0) {
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/UserWakeupStore.java b/apex/jobscheduler/service/java/com/android/server/alarm/UserWakeupStore.java
index 7fc630c..dc5e341 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/UserWakeupStore.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/UserWakeupStore.java
@@ -98,12 +98,7 @@
*/
@GuardedBy("mUserWakeupLock")
private final SparseLongArray mUserStarts = new SparseLongArray();
- /**
- * A list of users that are in a phase after they have been started but before alarms were
- * initialized.
- */
- @GuardedBy("mUserWakeupLock")
- private final SparseLongArray mStartingUsers = new SparseLongArray();
+
private Executor mBackgroundExecutor;
private static final File USER_WAKEUP_DIR = new File(Environment.getDataSystemDirectory(),
ROOT_DIR_NAME);
@@ -124,9 +119,6 @@
*/
public void addUserWakeup(int userId, long alarmTime) {
synchronized (mUserWakeupLock) {
- // This should not be needed, but if an app in the user is scheduling an alarm clock, we
- // consider the user start complete. There is a dedicated removal when user is started.
- mStartingUsers.delete(userId);
mUserStarts.put(userId, alarmTime - BUFFER_TIME_MS + getUserWakeupOffset());
}
updateUserListFile();
@@ -192,23 +184,10 @@
}
/**
- * Move user from wakeup list to starting user list.
+ * Remove scheduled user wakeup from the list when it is started.
*/
public void onUserStarting(int userId) {
- synchronized (mUserWakeupLock) {
- final long wakeup = getWakeupTimeForUser(userId);
- if (wakeup >= 0) {
- mStartingUsers.put(userId, wakeup);
- mUserStarts.delete(userId);
- }
- }
- }
-
- /**
- * Remove userId from starting user list once start is complete.
- */
- public void onUserStarted(int userId) {
- if (deleteWakeupFromStartingUsers(userId)) {
+ if (deleteWakeupFromUserStarts(userId)) {
updateUserListFile();
}
}
@@ -217,7 +196,7 @@
* Remove userId from the store when the user is removed.
*/
public void onUserRemoved(int userId) {
- if (deleteWakeupFromUserStarts(userId) || deleteWakeupFromStartingUsers(userId)) {
+ if (deleteWakeupFromUserStarts(userId)) {
updateUserListFile();
}
}
@@ -227,29 +206,14 @@
* @return true if an entry is found and the list of wakeups changes.
*/
private boolean deleteWakeupFromUserStarts(int userId) {
- int index;
synchronized (mUserWakeupLock) {
- index = mUserStarts.indexOfKey(userId);
+ final int index = mUserStarts.indexOfKey(userId);
if (index >= 0) {
mUserStarts.removeAt(index);
+ return true;
}
+ return false;
}
- return index >= 0;
- }
-
- /**
- * Remove wakeup for a given userId from mStartingUsers.
- * @return true if an entry is found and the list of wakeups changes.
- */
- private boolean deleteWakeupFromStartingUsers(int userId) {
- int index;
- synchronized (mUserWakeupLock) {
- index = mStartingUsers.indexOfKey(userId);
- if (index >= 0) {
- mStartingUsers.removeAt(index);
- }
- }
- return index >= 0;
}
/**
@@ -299,9 +263,6 @@
for (int i = 0; i < mUserStarts.size(); i++) {
listOfUsers.add(new Pair<>(mUserStarts.keyAt(i), mUserStarts.valueAt(i)));
}
- for (int i = 0; i < mStartingUsers.size(); i++) {
- listOfUsers.add(new Pair<>(mStartingUsers.keyAt(i), mStartingUsers.valueAt(i)));
- }
}
Collections.sort(listOfUsers, Comparator.comparingLong(pair -> pair.second));
for (int i = 0; i < listOfUsers.size(); i++) {
@@ -329,7 +290,6 @@
}
synchronized (mUserWakeupLock) {
mUserStarts.clear();
- mStartingUsers.clear();
}
try (FileInputStream fis = userWakeupFile.openRead()) {
final TypedXmlPullParser parser = Xml.resolvePullParser(fis);
@@ -396,14 +356,6 @@
TimeUtils.formatDuration(mUserStarts.valueAt(i), nowELAPSED, pw);
pw.println();
}
- pw.println(mStartingUsers.size() + " starting users: ");
- for (int i = 0; i < mStartingUsers.size(); i++) {
- pw.print("UserId: ");
- pw.print(mStartingUsers.keyAt(i));
- pw.print(", userStartTime: ");
- TimeUtils.formatDuration(mStartingUsers.valueAt(i), nowELAPSED, pw);
- pw.println();
- }
pw.decreaseIndent();
}
}
diff --git a/api/Android.bp b/api/Android.bp
index 3fa9c60..26899ea 100644
--- a/api/Android.bp
+++ b/api/Android.bp
@@ -157,6 +157,7 @@
genrule {
name: "frameworks-base-api-system-current-compat",
srcs: [
+ ":android.api.public.latest",
":android.api.system.latest",
":android-incompatibilities.api.system.latest",
":frameworks-base-api-current.txt",
@@ -165,33 +166,35 @@
out: ["updated-baseline.txt"],
tools: ["metalava"],
cmd: metalava_cmd +
+ "--check-compatibility:api:released $(location :android.api.public.latest) " +
"--check-compatibility:api:released $(location :android.api.system.latest) " +
- "--check-compatibility:base $(location :frameworks-base-api-current.txt) " +
"--baseline:compatibility:released $(location :android-incompatibilities.api.system.latest) " +
"--update-baseline:compatibility:released $(genDir)/updated-baseline.txt " +
+ "$(location :frameworks-base-api-current.txt) " +
"$(location :frameworks-base-api-system-current.txt)",
}
genrule {
name: "frameworks-base-api-module-lib-current-compat",
srcs: [
+ ":android.api.public.latest",
+ ":android.api.system.latest",
":android.api.module-lib.latest",
":android-incompatibilities.api.module-lib.latest",
":frameworks-base-api-current.txt",
+ ":frameworks-base-api-system-current.txt",
":frameworks-base-api-module-lib-current.txt",
],
out: ["updated-baseline.txt"],
tools: ["metalava"],
cmd: metalava_cmd +
+ "--check-compatibility:api:released $(location :android.api.public.latest) " +
+ "--check-compatibility:api:released $(location :android.api.system.latest) " +
"--check-compatibility:api:released $(location :android.api.module-lib.latest) " +
- // Note: having "public" be the base of module-lib is not perfect -- it should
- // ideally be a merged public+system (which metalava is not currently able to generate).
- // This "base" will help when migrating from MODULE_LIBS -> public, but not when
- // migrating from MODULE_LIBS -> system (where it needs to instead be listed as
- // an incompatibility).
- "--check-compatibility:base $(location :frameworks-base-api-current.txt) " +
"--baseline:compatibility:released $(location :android-incompatibilities.api.module-lib.latest) " +
"--update-baseline:compatibility:released $(genDir)/updated-baseline.txt " +
+ "$(location :frameworks-base-api-current.txt) " +
+ "$(location :frameworks-base-api-system-current.txt) " +
"$(location :frameworks-base-api-module-lib-current.txt)",
}
diff --git a/core/api/current.txt b/core/api/current.txt
index 5eeb299..6e42fe3 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -3453,6 +3453,8 @@
field public static final int GLOBAL_ACTION_HOME = 2; // 0x2
field public static final int GLOBAL_ACTION_KEYCODE_HEADSETHOOK = 10; // 0xa
field public static final int GLOBAL_ACTION_LOCK_SCREEN = 8; // 0x8
+ field @FlaggedApi("android.view.accessibility.global_action_media_play_pause") public static final int GLOBAL_ACTION_MEDIA_PLAY_PAUSE = 22; // 0x16
+ field @FlaggedApi("android.view.accessibility.global_action_menu") public static final int GLOBAL_ACTION_MENU = 21; // 0x15
field public static final int GLOBAL_ACTION_NOTIFICATIONS = 4; // 0x4
field public static final int GLOBAL_ACTION_POWER_DIALOG = 6; // 0x6
field public static final int GLOBAL_ACTION_QUICK_SETTINGS = 5; // 0x5
@@ -6699,7 +6701,7 @@
method @NonNull public android.app.Notification.Builder setExtras(android.os.Bundle);
method @NonNull public android.app.Notification.Builder setFlag(int, boolean);
method @NonNull public android.app.Notification.Builder setForegroundServiceBehavior(int);
- method @NonNull public android.app.Notification.Builder setFullScreenIntent(android.app.PendingIntent, boolean);
+ method @NonNull @RequiresPermission(android.Manifest.permission.USE_FULL_SCREEN_INTENT) public android.app.Notification.Builder setFullScreenIntent(android.app.PendingIntent, boolean);
method @NonNull public android.app.Notification.Builder setGroup(String);
method @NonNull public android.app.Notification.Builder setGroupAlertBehavior(int);
method @NonNull public android.app.Notification.Builder setGroupSummary(boolean);
@@ -9824,6 +9826,7 @@
method public void onAssociationPending(@NonNull android.content.IntentSender);
method @Deprecated public void onDeviceFound(@NonNull android.content.IntentSender);
method public abstract void onFailure(@Nullable CharSequence);
+ method @FlaggedApi("android.companion.association_failure_code") public void onFailure(int);
}
public abstract class CompanionDeviceService extends android.app.Service {
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 50d97cf..5393475 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -12886,7 +12886,14 @@
field public static final String KEY_SENSITIVE_CONTENT = "key_sensitive_content";
field public static final String KEY_SNOOZE_CRITERIA = "key_snooze_criteria";
field public static final String KEY_TEXT_REPLIES = "key_text_replies";
+ field @FlaggedApi("android.service.notification.notification_classification") public static final String KEY_TYPE = "key_type";
field public static final String KEY_USER_SENTIMENT = "key_user_sentiment";
+ field @FlaggedApi("android.service.notification.notification_classification") public static final int TYPE_CONTENT_RECOMMENDATION = 4; // 0x4
+ field @FlaggedApi("android.service.notification.notification_classification") public static final int TYPE_NEWS = 3; // 0x3
+ field @FlaggedApi("android.service.notification.notification_classification") public static final int TYPE_OTHER = 0; // 0x0
+ field @FlaggedApi("android.service.notification.notification_classification") public static final int TYPE_PROMOTION = 1; // 0x1
+ field @FlaggedApi("android.service.notification.notification_classification") public static final int TYPE_SOCIAL_MEDIA = 2; // 0x2
+ field @FlaggedApi("android.service.notification.notification_classification") public static final int TYPE_UNKNOWN = -1; // 0xffffffff
}
public abstract class NotificationAssistantService extends android.service.notification.NotificationListenerService {
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index c2f960f..d899511 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -379,6 +379,10 @@
method public void setImportantConversation(boolean);
method public void setOriginalImportance(int);
method public void setUserVisibleTaskShown(boolean);
+ field @FlaggedApi("android.service.notification.notification_classification") public static final String NEWS_ID = "android.app.news";
+ field @FlaggedApi("android.service.notification.notification_classification") public static final String PROMOTIONS_ID = "android.app.promotions";
+ field @FlaggedApi("android.service.notification.notification_classification") public static final String RECS_ID = "android.app.recs";
+ field @FlaggedApi("android.service.notification.notification_classification") public static final String SOCIAL_MEDIA_ID = "android.app.social";
}
public final class NotificationChannelGroup implements android.os.Parcelable {
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index fd9600c..19ffc17f 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -67,6 +67,7 @@
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
import android.view.accessibility.AccessibilityWindowInfo;
+import android.view.accessibility.Flags;
import android.view.inputmethod.EditorInfo;
import com.android.internal.annotations.VisibleForTesting;
@@ -625,6 +626,18 @@
*/
public static final int GLOBAL_ACTION_DPAD_CENTER = 20;
+ /**
+ * Action to trigger menu key event.
+ */
+ @FlaggedApi(Flags.FLAG_GLOBAL_ACTION_MENU)
+ public static final int GLOBAL_ACTION_MENU = 21;
+
+ /**
+ * Action to trigger media play/pause key event.
+ */
+ @FlaggedApi(Flags.FLAG_GLOBAL_ACTION_MEDIA_PLAY_PAUSE)
+ public static final int GLOBAL_ACTION_MEDIA_PLAY_PAUSE = 22;
+
private static final String LOG_TAG = "AccessibilityService";
/**
diff --git a/core/java/android/app/AppCompatCallbacks.java b/core/java/android/app/AppCompatCallbacks.java
index f2debfc..4bfa3b3 100644
--- a/core/java/android/app/AppCompatCallbacks.java
+++ b/core/java/android/app/AppCompatCallbacks.java
@@ -82,7 +82,7 @@
private void reportChange(long changeId, int state, boolean isLoggable) {
int uid = Process.myUid();
- mChangeReporter.reportChange(uid, changeId, state, isLoggable);
+ mChangeReporter.reportChange(uid, changeId, state, false, isLoggable);
}
}
diff --git a/core/java/android/app/AutomaticZenRule.java b/core/java/android/app/AutomaticZenRule.java
index 1925380..62b5412 100644
--- a/core/java/android/app/AutomaticZenRule.java
+++ b/core/java/android/app/AutomaticZenRule.java
@@ -397,6 +397,23 @@
}
/**
+ * Sets the component name of the
+ * {@link android.service.notification.ConditionProviderService} that manages this rule
+ * (but note that {@link android.service.notification.ConditionProviderService} is
+ * deprecated in favor of using {@link NotificationManager#setAutomaticZenRuleState} to
+ * notify the system about the state of your rule).
+ *
+ * <p>This is exclusive with {@link #setConfigurationActivity}; rules where a configuration
+ * activity is set will not use the component set here to determine whether the rule
+ * should be active.
+ *
+ * @hide
+ */
+ public void setOwner(@Nullable ComponentName owner) {
+ this.owner = owner;
+ }
+
+ /**
* Sets the configuration activity - an activity that handles
* {@link NotificationManager#ACTION_AUTOMATIC_ZEN_RULE} that shows the user more information
* about this rule and/or allows them to configure it. This is required to be non-null for rules
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 3b9a5d3..baed4fd 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -2303,19 +2303,26 @@
&& PermissionManager.DEVICE_AWARE_PERMISSIONS.contains(permission)) {
VirtualDeviceManager virtualDeviceManager =
getSystemService(VirtualDeviceManager.class);
- VirtualDevice virtualDevice = virtualDeviceManager.getVirtualDevice(deviceId);
- if (virtualDevice != null) {
- if ((Objects.equals(permission, Manifest.permission.RECORD_AUDIO)
- && !virtualDevice.hasCustomAudioInputSupport())
- || (Objects.equals(permission, Manifest.permission.CAMERA)
- && !virtualDevice.hasCustomCameraSupport())) {
- deviceId = Context.DEVICE_ID_DEFAULT;
- }
- } else {
+ if (virtualDeviceManager == null) {
Slog.e(
TAG,
- "virtualDevice is not found when device id is not default. deviceId = "
+ "VDM is not enabled when device id is not default. deviceId = "
+ deviceId);
+ } else {
+ VirtualDevice virtualDevice = virtualDeviceManager.getVirtualDevice(deviceId);
+ if (virtualDevice != null) {
+ if ((Objects.equals(permission, Manifest.permission.RECORD_AUDIO)
+ && !virtualDevice.hasCustomAudioInputSupport())
+ || (Objects.equals(permission, Manifest.permission.CAMERA)
+ && !virtualDevice.hasCustomCameraSupport())) {
+ deviceId = Context.DEVICE_ID_DEFAULT;
+ }
+ } else {
+ Slog.e(
+ TAG,
+ "virtualDevice is not found when device id is not default. deviceId = "
+ + deviceId);
+ }
}
}
@@ -3169,6 +3176,11 @@
public void updateDeviceId(int updatedDeviceId) {
if (updatedDeviceId != Context.DEVICE_ID_DEFAULT) {
VirtualDeviceManager vdm = getSystemService(VirtualDeviceManager.class);
+ if (vdm == null) {
+ throw new IllegalArgumentException(
+ "VDM is not enabled when updating to non-default device id: "
+ + updatedDeviceId);
+ }
if (!vdm.isValidVirtualDeviceId(updatedDeviceId)) {
throw new IllegalArgumentException(
"Not a valid ID of the default device or any virtual device: "
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index ffb920b..15b13dc 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -757,15 +757,6 @@
void addStartInfoTimestamp(int key, long timestampNs, int userId);
/**
- * Reports view related timestamps to be added to the calling apps most
- * recent {@link ApplicationStartInfo}.
- *
- * @param renderThreadDrawStartTimeNs Clock monotonic time in nanoseconds of RenderThread draw start
- * @param framePresentedTimeNs Clock monotonic time in nanoseconds of frame presented
- */
- oneway void reportStartInfoViewTimestamps(long renderThreadDrawStartTimeNs, long framePresentedTimeNs);
-
- /**
* Return a list of {@link ApplicationExitInfo} records.
*
* <p class="note"> Note: System stores these historical information in a ring buffer, older
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index a1c4267..aea15e1 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -5058,6 +5058,7 @@
* @see Notification#fullScreenIntent
*/
@NonNull
+ @RequiresPermission(android.Manifest.permission.USE_FULL_SCREEN_INTENT)
public Builder setFullScreenIntent(PendingIntent intent, boolean highPriority) {
mN.fullScreenIntent = intent;
setFlag(FLAG_HIGH_PRIORITY, highPriority);
@@ -6050,6 +6051,7 @@
bindProfileBadge(contentView, p);
bindAlertedIcon(contentView, p);
bindExpandButton(contentView, p);
+ bindCloseButton(contentView, p);
mN.mUsesStandardHeader = true;
}
@@ -6071,6 +6073,15 @@
contentView.setInt(R.id.expand_button, "setHighlightPillColor", pillColor);
}
+ private void bindCloseButton(RemoteViews contentView, StandardTemplateParams p) {
+ // set default colors
+ int bgColor = getBackgroundColor(p);
+ int backgroundColor = Colors.flattenAlpha(getColors(p).getProtectionColor(), bgColor);
+ int foregroundColor = Colors.flattenAlpha(getPrimaryTextColor(p), backgroundColor);
+ contentView.setInt(R.id.close_button, "setForegroundColor", foregroundColor);
+ contentView.setInt(R.id.close_button, "setBackgroundColor", backgroundColor);
+ }
+
private void bindHeaderChronometerAndTime(RemoteViews contentView,
StandardTemplateParams p, boolean hasTextToLeft) {
if (!p.mHideTime && showsTimeOrChronometer()) {
diff --git a/core/java/android/app/NotificationChannel.java b/core/java/android/app/NotificationChannel.java
index 3f6c81b..326d7ce 100644
--- a/core/java/android/app/NotificationChannel.java
+++ b/core/java/android/app/NotificationChannel.java
@@ -72,6 +72,35 @@
public static final String DEFAULT_CHANNEL_ID = "miscellaneous";
/**
+ * A reserved id for a system channel reserved for promotional notifications.
+ * @hide
+ */
+ @TestApi
+ @FlaggedApi(android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION)
+ public static final String PROMOTIONS_ID = "android.app.promotions";
+ /**
+ * A reserved id for a system channel reserved for non-conversation social media notifications.
+ * @hide
+ */
+ @TestApi
+ @FlaggedApi(android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION)
+ public static final String SOCIAL_MEDIA_ID = "android.app.social";
+ /**
+ * A reserved id for a system channel reserved for news notifications.
+ * @hide
+ */
+ @TestApi
+ @FlaggedApi(android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION)
+ public static final String NEWS_ID = "android.app.news";
+ /**
+ * A reserved id for a system channel reserved for content recommendation notifications.
+ * @hide
+ */
+ @TestApi
+ @FlaggedApi(android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION)
+ public static final String RECS_ID = "android.app.recs";
+
+ /**
* The formatter used by the system to create an id for notification
* channels when it automatically creates conversation channels on behalf of an app. The format
* string takes two arguments, in this order: the
diff --git a/core/java/android/appwidget/flags.aconfig b/core/java/android/appwidget/flags.aconfig
index 18cfca6..4e0379e 100644
--- a/core/java/android/appwidget/flags.aconfig
+++ b/core/java/android/appwidget/flags.aconfig
@@ -50,3 +50,10 @@
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ name: "remote_views_proto"
+ namespace: "app_widgets"
+ description: "Enable support for persisting RemoteViews previews to Protobuf"
+ bug: "306546610"
+}
diff --git a/core/java/android/companion/CompanionDeviceManager.java b/core/java/android/companion/CompanionDeviceManager.java
index b4ad1c8..34cfa58 100644
--- a/core/java/android/companion/CompanionDeviceManager.java
+++ b/core/java/android/companion/CompanionDeviceManager.java
@@ -21,6 +21,8 @@
import static android.Manifest.permission.REQUEST_COMPANION_PROFILE_COMPUTER;
import static android.Manifest.permission.REQUEST_COMPANION_PROFILE_WATCH;
+import static java.util.Collections.unmodifiableMap;
+
import android.annotation.CallbackExecutor;
import android.annotation.FlaggedApi;
import android.annotation.IntDef;
@@ -56,6 +58,7 @@
import android.os.RemoteException;
import android.os.UserHandle;
import android.service.notification.NotificationListenerService;
+import android.util.ArrayMap;
import android.util.ExceptionUtils;
import android.util.Log;
import android.util.SparseArray;
@@ -75,6 +78,7 @@
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
+import java.util.Map;
import java.util.Objects;
import java.util.concurrent.Executor;
import java.util.function.BiConsumer;
@@ -119,29 +123,31 @@
* is created successfully.
*/
public static final int RESULT_OK = -1;
-
+ //TODO(b/331459560) Need to update the java doc after API cut for W.
/**
* The result code to propagate back to the user activity, indicates if the association dialog
* is implicitly cancelled.
* E.g. phone is locked, switch to another app or press outside the dialog.
*/
public static final int RESULT_CANCELED = 0;
-
+ //TODO(b/331459560) Need to update the java doc after API cut for W.
/**
* The result code to propagate back to the user activity, indicates the association dialog
* is explicitly declined by the users.
*/
public static final int RESULT_USER_REJECTED = 1;
-
+ //TODO(b/331459560) Need to update the java doc after API cut for W.
/**
* The result code to propagate back to the user activity, indicates the association
* dialog is dismissed if there's no device found after 20 seconds.
*/
public static final int RESULT_DISCOVERY_TIMEOUT = 2;
-
+ //TODO(b/331459560) Need to update the java doc after API cut for W.
/**
* The result code to propagate back to the user activity, indicates the internal error
* in CompanionDeviceManager.
+ * E.g. Missing necessary permissions or duplicate {@link AssociationRequest}s when create the
+ * {@link AssociationInfo}.
*/
public static final int RESULT_INTERNAL_ERROR = 3;
@@ -368,12 +374,22 @@
*/
public void onAssociationCreated(@NonNull AssociationInfo associationInfo) {}
+ //TODO(b/331459560): Add deprecated and remove abstract after API cut for W.
/**
* Invoked if the association could not be created.
*
* @param error error message.
*/
public abstract void onFailure(@Nullable CharSequence error);
+
+ /**
+ * Invoked if the association could not be created.
+ *
+ * @param resultCode indicate the particular reason why the association
+ * could not be created.
+ */
+ @FlaggedApi(Flags.FLAG_ASSOCIATION_FAILURE_CODE)
+ public void onFailure(@ResultCode int resultCode) {}
}
private final ICompanionDeviceManager mService;
@@ -1803,8 +1819,12 @@
}
@Override
- public void onFailure(CharSequence error) throws RemoteException {
- execute(mCallback::onFailure, error);
+ public void onFailure(@ResultCode int resultCode) {
+ if (Flags.associationFailureCode()) {
+ execute(mCallback::onFailure, resultCode);
+ }
+
+ execute(mCallback::onFailure, RESULT_CODE_TO_REASON.get(resultCode));
}
private <T> void execute(Consumer<T> callback, T arg) {
@@ -1988,4 +2008,15 @@
}
}
}
+
+ private static final Map<Integer, String> RESULT_CODE_TO_REASON;
+ static {
+ final Map<Integer, String> map = new ArrayMap<>();
+ map.put(RESULT_CANCELED, REASON_CANCELED);
+ map.put(RESULT_USER_REJECTED, REASON_USER_REJECTED);
+ map.put(RESULT_DISCOVERY_TIMEOUT, REASON_DISCOVERY_TIMEOUT);
+ map.put(RESULT_INTERNAL_ERROR, REASON_INTERNAL_ERROR);
+
+ RESULT_CODE_TO_REASON = unmodifiableMap(map);
+ }
}
diff --git a/core/java/android/companion/IAssociationRequestCallback.aidl b/core/java/android/companion/IAssociationRequestCallback.aidl
index 8cc2a71..b1be30a 100644
--- a/core/java/android/companion/IAssociationRequestCallback.aidl
+++ b/core/java/android/companion/IAssociationRequestCallback.aidl
@@ -25,5 +25,5 @@
oneway void onAssociationCreated(in AssociationInfo associationInfo);
- oneway void onFailure(in CharSequence error);
+ oneway void onFailure(in int resultCode);
}
\ No newline at end of file
diff --git a/core/java/android/companion/flags.aconfig b/core/java/android/companion/flags.aconfig
index fd4ba83..ee9114f 100644
--- a/core/java/android/companion/flags.aconfig
+++ b/core/java/android/companion/flags.aconfig
@@ -53,4 +53,12 @@
namespace: "companion"
description: "Unpair with an associated bluetooth device"
bug: "322237619"
-}
\ No newline at end of file
+}
+
+flag {
+ name: "association_failure_code"
+ is_exported: true
+ namespace: "companion"
+ description: "Enable association failure code API"
+ bug: "331459560"
+}
diff --git a/core/java/android/content/ComponentCallbacks.java b/core/java/android/content/ComponentCallbacks.java
index fb9536f..3acb373 100644
--- a/core/java/android/content/ComponentCallbacks.java
+++ b/core/java/android/content/ComponentCallbacks.java
@@ -58,7 +58,9 @@
* @deprecated Since API level 14 this is superseded by
* {@link ComponentCallbacks2#onTrimMemory}.
* Since API level 34 this is never called.
- * Apps targeting API level 34 and above may provide an empty implementation.
+ * If you're overriding ComponentCallbacks2#onTrimMemory and
+ * your minSdkVersion is greater than API 14, you can provide
+ * an empty implementation for this method.
*/
@Deprecated
void onLowMemory();
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 4fcf6b6..24fd000 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -4451,7 +4451,8 @@
* @see #DISPLAY_HASH_SERVICE
* @see android.view.displayhash.DisplayHashManager
*/
- public abstract @Nullable Object getSystemService(@ServiceName @NonNull String name);
+ // TODO(b/347269120): Re-add @Nullable
+ public abstract Object getSystemService(@ServiceName @NonNull String name);
/**
* Return the handle to a system-level service by class.
@@ -4495,7 +4496,8 @@
* <b>never</b> throw a {@link RuntimeException} if the name is not supported.
*/
@SuppressWarnings("unchecked")
- public final @Nullable <T> T getSystemService(@NonNull Class<T> serviceClass) {
+ // TODO(b/347269120): Re-add @Nullable
+ public final <T> T getSystemService(@NonNull Class<T> serviceClass) {
// Because subclasses may override getSystemService(String) we cannot
// perform a lookup by class alone. We must first map the class to its
// service name then invoke the string-based method.
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index e0cf0a5..a475c29 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -932,7 +932,8 @@
}
@Override
- public @Nullable Object getSystemService(String name) {
+ // TODO(b/347269120): Re-add @Nullable
+ public Object getSystemService(String name) {
return mBase.getSystemService(name);
}
diff --git a/core/java/android/content/OWNERS b/core/java/android/content/OWNERS
index a37408b..6d9dc45 100644
--- a/core/java/android/content/OWNERS
+++ b/core/java/android/content/OWNERS
@@ -14,3 +14,4 @@
per-file ComponentCallbacksController = charlesccchen@google.com
per-file AttributionSource* = file:/core/java/android/permission/OWNERS
per-file Broadcast* = file:/BROADCASTS_OWNERS
+per-file ComponentCallbacks*.java = file:/PERFORMANCE_OWNERS
\ No newline at end of file
diff --git a/core/java/android/content/pm/dex/OWNERS b/core/java/android/content/pm/dex/OWNERS
index 267e5d58..558b5f7 100644
--- a/core/java/android/content/pm/dex/OWNERS
+++ b/core/java/android/content/pm/dex/OWNERS
@@ -1,7 +1,6 @@
# Bug component: 86431
-toddke@android.com
-toddke@google.com
patb@google.com
-calin@google.com
ngeoffray@google.com
+jiakaiz@google.com
+mast@google.com
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index 32d2a6f..c2424e8 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -347,7 +347,9 @@
VirtualDeviceManager virtualDeviceManager =
context.getSystemService(VirtualDeviceManager.class);
- return virtualDeviceManager.getDevicePolicy(context.getDeviceId(), POLICY_TYPE_CAMERA);
+ return virtualDeviceManager == null
+ ? DEVICE_POLICY_DEFAULT
+ : virtualDeviceManager.getDevicePolicy(context.getDeviceId(), POLICY_TYPE_CAMERA);
}
/**
diff --git a/core/java/android/hardware/OWNERS b/core/java/android/hardware/OWNERS
index d2a2f12..51ad151 100644
--- a/core/java/android/hardware/OWNERS
+++ b/core/java/android/hardware/OWNERS
@@ -5,7 +5,7 @@
sumir@google.com
# Camera
-per-file *Camera*=cychen@google.com,epeev@google.com,etalvala@google.com,shuzhenwang@google.com,yinchiayeh@google.com,zhijunhe@google.com,jchowdhary@google.com
+per-file *Camera*=cychen@google.com,epeev@google.com,etalvala@google.com,shuzhenwang@google.com,zhijunhe@google.com,jchowdhary@google.com
# Sensor Privacy
per-file *SensorPrivacy* = file:platform/frameworks/native:/libs/sensorprivacy/OWNERS
diff --git a/core/java/android/hardware/biometrics/BiometricManager.java b/core/java/android/hardware/biometrics/BiometricManager.java
index fdd8b04..678bd6b 100644
--- a/core/java/android/hardware/biometrics/BiometricManager.java
+++ b/core/java/android/hardware/biometrics/BiometricManager.java
@@ -137,6 +137,7 @@
BIOMETRIC_WEAK,
BIOMETRIC_CONVENIENCE,
DEVICE_CREDENTIAL,
+ MANDATORY_BIOMETRICS,
})
@Retention(RetentionPolicy.SOURCE)
@interface Types {}
@@ -214,6 +215,21 @@
*/
int DEVICE_CREDENTIAL = 1 << 15;
+ /**
+ * The bit is used to request for mandatory biometrics.
+ *
+ * <p> The requirements to trigger mandatory biometrics are as follows:
+ * 1. User must have enabled the toggle for mandatory biometrics is settings
+ * 2. User must have enrollments for all {@link #BIOMETRIC_STRONG} sensors available
+ * 3. The device must not be in a trusted location
+ * </p>
+ *
+ * <p> If all the above conditions are satisfied, only {@link #BIOMETRIC_STRONG} sensors
+ * will be eligible for authentication, and device credential fallback will be dropped.
+ * @hide
+ */
+ int MANDATORY_BIOMETRICS = 1 << 16;
+
}
/**
diff --git a/core/java/android/hardware/biometrics/BiometricPrompt.java b/core/java/android/hardware/biometrics/BiometricPrompt.java
index 37a2df8..42f5fc8 100644
--- a/core/java/android/hardware/biometrics/BiometricPrompt.java
+++ b/core/java/android/hardware/biometrics/BiometricPrompt.java
@@ -794,10 +794,15 @@
public void onDialogDismissed(int reason) {
// Check the reason and invoke OnClickListener(s) if necessary
if (reason == DISMISSED_REASON_NEGATIVE) {
- mNegativeButtonInfo.executor.execute(() -> {
- mNegativeButtonInfo.listener.onClick(null, DialogInterface.BUTTON_NEGATIVE);
- mIsPromptShowing = false;
- });
+ if (mNegativeButtonInfo != null) {
+ mNegativeButtonInfo.executor.execute(() -> {
+ mNegativeButtonInfo.listener.onClick(null, DialogInterface.BUTTON_NEGATIVE);
+ mIsPromptShowing = false;
+ });
+ } else {
+ mAuthenticationCallback.onAuthenticationError(BIOMETRIC_ERROR_USER_CANCELED,
+ null /* errString */);
+ }
} else if (reason == DISMISSED_REASON_CONTENT_VIEW_MORE_OPTIONS) {
if (mContentViewMoreOptionsButtonInfo != null) {
mContentViewMoreOptionsButtonInfo.executor.execute(() -> {
diff --git a/core/java/android/hardware/biometrics/PromptInfo.java b/core/java/android/hardware/biometrics/PromptInfo.java
index ba9f30d..901f6b7 100644
--- a/core/java/android/hardware/biometrics/PromptInfo.java
+++ b/core/java/android/hardware/biometrics/PromptInfo.java
@@ -195,6 +195,10 @@
return true;
} else if (mContentView != null && isContentViewMoreOptionsButtonUsed()) {
return true;
+ } else if (Flags.mandatoryBiometrics()
+ && (mAuthenticators & BiometricManager.Authenticators.MANDATORY_BIOMETRICS)
+ != 0) {
+ return true;
}
return false;
}
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index 708f8a1..9eb9745 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -581,7 +581,9 @@
if (mVirtualDeviceManager == null) {
mVirtualDeviceManager = context.getSystemService(VirtualDeviceManager.class);
}
- return mVirtualDeviceManager.getDevicePolicy(context.getDeviceId(), POLICY_TYPE_CAMERA);
+ return mVirtualDeviceManager == null
+ ? DEVICE_POLICY_DEFAULT
+ : mVirtualDeviceManager.getDevicePolicy(context.getDeviceId(), POLICY_TYPE_CAMERA);
}
// TODO(b/147726300): Investigate how to support foldables/multi-display devices.
diff --git a/core/java/android/hardware/radio/TunerCallbackAdapter.java b/core/java/android/hardware/radio/TunerCallbackAdapter.java
index f9a2dbb..b1b4de3 100644
--- a/core/java/android/hardware/radio/TunerCallbackAdapter.java
+++ b/core/java/android/hardware/radio/TunerCallbackAdapter.java
@@ -63,48 +63,53 @@
}
void close() {
+ ProgramList programList;
synchronized (mLock) {
- if (mProgramList != null) {
- mProgramList.close();
+ if (mProgramList == null) {
+ return;
}
+ programList = mProgramList;
}
+ programList.close();
}
void setProgramListObserver(@Nullable ProgramList programList,
ProgramList.OnCloseListener closeListener) {
Objects.requireNonNull(closeListener, "CloseListener cannot be null");
+ ProgramList prevProgramList;
synchronized (mLock) {
- if (mProgramList != null) {
- Log.w(TAG, "Previous program list observer wasn't properly closed, closing it...");
- mProgramList.close();
- }
+ prevProgramList = mProgramList;
mProgramList = programList;
- if (programList == null) {
- return;
- }
- programList.setOnCloseListener(() -> {
- synchronized (mLock) {
- if (mProgramList != programList) {
- return;
- }
- mProgramList = null;
- mLastCompleteList = null;
- }
- closeListener.onClose();
- });
- programList.addOnCompleteListener(() -> {
- synchronized (mLock) {
- if (mProgramList != programList) {
- return;
- }
- mLastCompleteList = programList.toList();
- if (mDelayedCompleteCallback) {
- Log.d(TAG, "Sending delayed onBackgroundScanComplete callback");
- sendBackgroundScanCompleteLocked();
- }
- }
- });
}
+ if (prevProgramList != null) {
+ Log.w(TAG, "Previous program list observer wasn't properly closed, closing it...");
+ prevProgramList.close();
+ }
+ if (programList == null) {
+ return;
+ }
+ programList.setOnCloseListener(() -> {
+ synchronized (mLock) {
+ if (mProgramList != programList) {
+ return;
+ }
+ mProgramList = null;
+ mLastCompleteList = null;
+ }
+ closeListener.onClose();
+ });
+ programList.addOnCompleteListener(() -> {
+ synchronized (mLock) {
+ if (mProgramList != programList) {
+ return;
+ }
+ mLastCompleteList = programList.toList();
+ if (mDelayedCompleteCallback) {
+ Log.d(TAG, "Sending delayed onBackgroundScanComplete callback");
+ sendBackgroundScanCompleteLocked();
+ }
+ }
+ });
}
@Nullable List<RadioManager.ProgramInfo> getLastCompleteList() {
@@ -245,12 +250,14 @@
@Override
public void onProgramListUpdated(ProgramList.Chunk chunk) {
mHandler.post(() -> {
+ ProgramList programList;
synchronized (mLock) {
if (mProgramList == null) {
return;
}
- mProgramList.apply(Objects.requireNonNull(chunk, "Chunk cannot be null"));
+ programList = mProgramList;
}
+ programList.apply(Objects.requireNonNull(chunk, "Chunk cannot be null"));
});
}
diff --git a/core/java/android/net/OWNERS b/core/java/android/net/OWNERS
index feeef55..92ea0cf 100644
--- a/core/java/android/net/OWNERS
+++ b/core/java/android/net/OWNERS
@@ -3,6 +3,6 @@
include platform/frameworks/base:/services/core/java/com/android/server/net/OWNERS
per-file **IpSec* = file:/services/core/java/com/android/server/vcn/OWNERS
-per-file SSL*,Uri*,Url* = prb@google.com,oth@google.com,narayan@google.com,ngeoffray@google.com
+per-file SSL*,Uri*,Url* = prb@google.com,sorinbasca@google.com,narayan@google.com,ngeoffray@google.com
per-file SntpClient* = file:/services/core/java/com/android/server/timedetector/OWNERS
per-file Uri.java,Uri.aidl = varunshah@google.com
diff --git a/core/java/android/os/vibrator/flags.aconfig b/core/java/android/os/vibrator/flags.aconfig
index eda755c..b01ffe5 100644
--- a/core/java/android/os/vibrator/flags.aconfig
+++ b/core/java/android/os/vibrator/flags.aconfig
@@ -31,3 +31,14 @@
description: "Enables the adaptive haptics feature"
bug: "305961689"
}
+
+flag {
+ namespace: "haptics"
+ name: "cancel_by_appops"
+ description: "Cancels ongoing vibrations when the appops mode changes to disallow them"
+ bug: "230745615"
+ is_fixed_read_only: true
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/core/java/android/permission/PermissionUsageHelper.java b/core/java/android/permission/PermissionUsageHelper.java
index 141ffc9..a698b18 100644
--- a/core/java/android/permission/PermissionUsageHelper.java
+++ b/core/java/android/permission/PermissionUsageHelper.java
@@ -374,20 +374,22 @@
public @NonNull List<PermissionGroupUsage> getOpUsageDataForAllDevices(
boolean includeMicrophoneUsage) {
List<PermissionGroupUsage> allUsages = new ArrayList<>();
- List<VirtualDevice> virtualDevices = mVirtualDeviceManager.getVirtualDevices();
- ArraySet<String> persistentDeviceIds = new ArraySet<>();
- for (int num = 0; num < virtualDevices.size(); num++) {
- persistentDeviceIds.add(virtualDevices.get(num).getPersistentDeviceId());
+ if (mVirtualDeviceManager != null) {
+ List<VirtualDevice> virtualDevices = mVirtualDeviceManager.getVirtualDevices();
+ ArraySet<String> persistentDeviceIds = new ArraySet<>();
+
+ for (int num = 0; num < virtualDevices.size(); num++) {
+ persistentDeviceIds.add(virtualDevices.get(num).getPersistentDeviceId());
+ }
+ persistentDeviceIds.add(VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT);
+
+ for (int index = 0; index < persistentDeviceIds.size(); index++) {
+ allUsages.addAll(
+ getOpUsageDataByDevice(includeMicrophoneUsage,
+ persistentDeviceIds.valueAt(index)));
+ }
}
- persistentDeviceIds.add(VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT);
-
- for (int index = 0; index < persistentDeviceIds.size(); index++) {
- allUsages.addAll(
- getOpUsageDataByDevice(includeMicrophoneUsage,
- persistentDeviceIds.valueAt(index)));
- }
-
return allUsages;
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index d91508f..4e8a04f 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -11046,6 +11046,12 @@
public static final String BIOMETRIC_APP_ENABLED = "biometric_app_enabled";
/**
+ * Whether or not mandatory biometrics is enabled.
+ * @hide
+ */
+ public static final String MANDATORY_BIOMETRICS = "mandatory_biometrics";
+
+ /**
* Whether or not active unlock triggers on wake.
* @hide
*/
diff --git a/core/java/android/service/dreams/DreamOverlayConnectionHandler.java b/core/java/android/service/dreams/DreamOverlayConnectionHandler.java
index 85a13c7..bc03400 100644
--- a/core/java/android/service/dreams/DreamOverlayConnectionHandler.java
+++ b/core/java/android/service/dreams/DreamOverlayConnectionHandler.java
@@ -27,7 +27,6 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ObservableServiceConnection;
-import com.android.internal.util.PersistentServiceConnection;
import java.util.ArrayList;
import java.util.List;
@@ -48,22 +47,20 @@
private static final int MSG_OVERLAY_CLIENT_READY = 3;
private final Handler mHandler;
- private final PersistentServiceConnection<IDreamOverlay> mConnection;
+ private final ObservableServiceConnection<IDreamOverlay> mConnection;
// Retrieved Client
private IDreamOverlayClient mClient;
// A list of pending requests to execute on the overlay.
private final List<Consumer<IDreamOverlayClient>> mConsumers = new ArrayList<>();
private final OverlayConnectionCallback mCallback;
+ private final Runnable mOnDisconnected;
DreamOverlayConnectionHandler(
Context context,
Looper looper,
Intent serviceIntent,
- int minConnectionDurationMs,
- int maxReconnectAttempts,
- int baseReconnectDelayMs) {
- this(context, looper, serviceIntent, minConnectionDurationMs, maxReconnectAttempts,
- baseReconnectDelayMs, new Injector());
+ Runnable onDisconnected) {
+ this(context, looper, serviceIntent, onDisconnected, new Injector());
}
@VisibleForTesting
@@ -71,20 +68,15 @@
Context context,
Looper looper,
Intent serviceIntent,
- int minConnectionDurationMs,
- int maxReconnectAttempts,
- int baseReconnectDelayMs,
+ Runnable onDisconnected,
Injector injector) {
mCallback = new OverlayConnectionCallback();
mHandler = new Handler(looper, new OverlayHandlerCallback());
+ mOnDisconnected = onDisconnected;
mConnection = injector.buildConnection(
context,
mHandler,
- serviceIntent,
- minConnectionDurationMs,
- maxReconnectAttempts,
- baseReconnectDelayMs
- );
+ serviceIntent);
}
/**
@@ -201,10 +193,14 @@
@Override
public void onDisconnected(ObservableServiceConnection<IDreamOverlay> connection,
int reason) {
+ Log.i(TAG, "Dream overlay disconnected, reason: " + reason);
mClient = null;
// Cancel any pending messages about the overlay being ready, since it is no
// longer ready.
mHandler.removeMessages(MSG_OVERLAY_CLIENT_READY);
+ if (mOnDisconnected != null) {
+ mOnDisconnected.run();
+ }
}
}
@@ -217,25 +213,18 @@
* Returns milliseconds since boot, not counting time spent in deep sleep. Can be overridden
* in tests with a fake clock.
*/
- public PersistentServiceConnection<IDreamOverlay> buildConnection(
+ public ObservableServiceConnection<IDreamOverlay> buildConnection(
Context context,
Handler handler,
- Intent serviceIntent,
- int minConnectionDurationMs,
- int maxReconnectAttempts,
- int baseReconnectDelayMs) {
+ Intent serviceIntent) {
final Executor executor = handler::post;
final int flags = Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE;
- return new PersistentServiceConnection<>(
+ return new ObservableServiceConnection<>(
context,
executor,
- handler,
IDreamOverlay.Stub::asInterface,
serviceIntent,
- flags,
- minConnectionDurationMs,
- maxReconnectAttempts,
- baseReconnectDelayMs
+ flags
);
}
}
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index a769643..8ecb1fb 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -182,6 +182,7 @@
/**
* The name of the dream manager service.
+ *
* @hide
*/
public static final String DREAM_SERVICE = "dreams";
@@ -222,12 +223,14 @@
/**
* Dream category for Low Light Dream
+ *
* @hide
*/
public static final int DREAM_CATEGORY_LOW_LIGHT = 1 << 0;
/**
* Dream category for Home Panel Dream
+ *
* @hide
*/
public static final int DREAM_CATEGORY_HOME_PANEL = 1 << 1;
@@ -295,7 +298,8 @@
void init(Context context);
/** Creates and returns the dream overlay connection */
- DreamOverlayConnectionHandler createOverlayConnection(ComponentName overlayComponent);
+ DreamOverlayConnectionHandler createOverlayConnection(ComponentName overlayComponent,
+ Runnable onDisconnected);
/** Returns the {@link DreamActivity} component */
ComponentName getDreamActivityComponent();
@@ -333,16 +337,15 @@
@Override
public DreamOverlayConnectionHandler createOverlayConnection(
- ComponentName overlayComponent) {
+ ComponentName overlayComponent,
+ Runnable onDisconnected) {
final Resources resources = mContext.getResources();
return new DreamOverlayConnectionHandler(
/* context= */ mContext,
Looper.getMainLooper(),
new Intent().setComponent(overlayComponent),
- resources.getInteger(R.integer.config_minDreamOverlayDurationMs),
- resources.getInteger(R.integer.config_dreamOverlayMaxReconnectAttempts),
- resources.getInteger(R.integer.config_dreamOverlayReconnectTimeoutMs));
+ onDisconnected);
}
@Override
@@ -1176,7 +1179,8 @@
// Connect to the overlay service if present.
if (!mWindowless && overlayComponent != null) {
- mOverlayConnection = mInjector.createOverlayConnection(overlayComponent);
+ mOverlayConnection = mInjector.createOverlayConnection(overlayComponent,
+ this::finish);
if (!mOverlayConnection.bind()) {
// Binding failed.
diff --git a/core/java/android/service/notification/Adjustment.java b/core/java/android/service/notification/Adjustment.java
index 9c14946..63410c7 100644
--- a/core/java/android/service/notification/Adjustment.java
+++ b/core/java/android/service/notification/Adjustment.java
@@ -15,6 +15,8 @@
*/
package android.service.notification;
+import android.annotation.FlaggedApi;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.StringDef;
@@ -62,7 +64,8 @@
KEY_IMPORTANCE_PROPOSAL,
KEY_SENSITIVE_CONTENT,
KEY_RANKING_SCORE,
- KEY_NOT_CONVERSATION
+ KEY_NOT_CONVERSATION,
+ KEY_TYPE
})
@Retention(RetentionPolicy.SOURCE)
public @interface Keys {}
@@ -172,6 +175,59 @@
public static final String KEY_NOT_CONVERSATION = "key_not_conversation";
/**
+ * Data type: int, the classification type of this notification. The OS may display
+ * notifications differently depending on the type, and may change the alerting level of the
+ * notification.
+ */
+ @FlaggedApi(Flags.FLAG_NOTIFICATION_CLASSIFICATION)
+ public static final String KEY_TYPE = "key_type";
+
+ /** @hide */
+ @IntDef(prefix = { "TYPE_" }, value = {
+ TYPE_UNKNOWN,
+ TYPE_OTHER,
+ TYPE_PROMOTION,
+ TYPE_SOCIAL_MEDIA,
+ TYPE_NEWS,
+ TYPE_CONTENT_RECOMMENDATION
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Types {}
+
+ /**
+ * The type of this notification is unknown.
+ */
+ @FlaggedApi(Flags.FLAG_NOTIFICATION_CLASSIFICATION)
+ public static final int TYPE_UNKNOWN = -1;
+ /**
+ * The type of this notification is not one of ones known to the NotificationAssistantService.
+ */
+ @FlaggedApi(Flags.FLAG_NOTIFICATION_CLASSIFICATION)
+ public static final int TYPE_OTHER = 0;
+ /**
+ * The type of this notification is a promotion/deal.
+ */
+ @FlaggedApi(Flags.FLAG_NOTIFICATION_CLASSIFICATION)
+ public static final int TYPE_PROMOTION = 1;
+ /**
+ * The type of this notification is social media content that isn't a
+ * {@link Notification.Builder#setShortcutId(String) conversation}.
+ */
+ @FlaggedApi(Flags.FLAG_NOTIFICATION_CLASSIFICATION)
+ public static final int TYPE_SOCIAL_MEDIA = 2;
+ /**
+ * The type of this notification is news.
+ */
+ @FlaggedApi(Flags.FLAG_NOTIFICATION_CLASSIFICATION)
+ public static final int TYPE_NEWS = 3;
+ /**
+ * The type of this notification is content recommendation, for example new videos or books the
+ * user may be interested in.
+ */
+ @FlaggedApi(Flags.FLAG_NOTIFICATION_CLASSIFICATION)
+ public static final int TYPE_CONTENT_RECOMMENDATION = 4;
+
+ /**
* Create a notification adjustment.
*
* @param pkg The package of the notification.
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index 7a0c016..a3afcce 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -2373,7 +2373,7 @@
public int userId = UserHandle.USER_NULL; // USER_NULL = unspecified - use current user
public String calName; // CalendarContract.Calendars.DISPLAY_NAME, or null for any
- public Long calendarId; // Calendars._ID, or null if restored from < Q calendar
+ @Nullable public Long calendarId; // Calendars._ID, or null if restored from < Q calendar
public int reply;
@Override
@@ -2405,6 +2405,33 @@
}
}
+ // ==== Built-in system condition: custom manual ====
+
+ public static final String CUSTOM_MANUAL_PATH = "custom_manual";
+ private static final Uri CUSTOM_MANUAL_CONDITION_ID =
+ new Uri.Builder().scheme(Condition.SCHEME)
+ .authority(SYSTEM_AUTHORITY)
+ .appendPath(CUSTOM_MANUAL_PATH)
+ .build();
+
+ /** Returns the condition id used for manual (not automatically triggered) custom rules. */
+ public static Uri toCustomManualConditionId() {
+ return CUSTOM_MANUAL_CONDITION_ID;
+ }
+
+ /**
+ * Returns whether the supplied {@link Uri} corresponds to the condition id used for manual (not
+ * automatically triggered) custom rules.
+ */
+ public static boolean isValidCustomManualConditionId(Uri conditionId) {
+ return CUSTOM_MANUAL_CONDITION_ID.equals(conditionId);
+ }
+
+ /** Returns the {@link ComponentName} of the custom manual condition provider. */
+ public static ComponentName getCustomManualConditionProvider() {
+ return new ComponentName(SYSTEM_AUTHORITY, "CustomManualConditionProvider");
+ }
+
// ==== End built-in system conditions ====
private static int[] tryParseHourAndMinute(String value) {
diff --git a/core/java/android/service/notification/flags.aconfig b/core/java/android/service/notification/flags.aconfig
index c5b4b41..bdef041 100644
--- a/core/java/android/service/notification/flags.aconfig
+++ b/core/java/android/service/notification/flags.aconfig
@@ -35,4 +35,12 @@
description: "Guards the new CallStyleNotificationEventsCallback"
bug: "305095040"
is_fixed_read_only: true
+}
+
+flag {
+ name: "notification_classification"
+ is_exported: true
+ namespace: "systemui"
+ description: "Allows the NAS to classify notifications"
+ bug: "343988084"
}
\ No newline at end of file
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index 8271caf..3161ff1 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -31,7 +31,6 @@
import static com.android.window.flags.Flags.noConsecutiveVisibilityEvents;
import static com.android.window.flags.Flags.noVisibilityEventOnDisplayStateChange;
import static com.android.window.flags.Flags.offloadColorExtraction;
-import static com.android.window.flags.Flags.windowSessionRelayoutInfo;
import android.animation.AnimationHandler;
import android.animation.Animator;
@@ -302,13 +301,10 @@
final InsetsState mInsetsState = new InsetsState();
final InsetsSourceControl.Array mTempControls = new InsetsSourceControl.Array();
final MergedConfiguration mMergedConfiguration = new MergedConfiguration();
- final Bundle mSyncSeqIdBundle = windowSessionRelayoutInfo() ? null : new Bundle();
SurfaceControl mSurfaceControl = new SurfaceControl();
- WindowRelayoutResult mRelayoutResult = windowSessionRelayoutInfo()
- ? new WindowRelayoutResult(mWinFrames, mMergedConfiguration, mSurfaceControl,
- mInsetsState, mTempControls)
- : null;
+ WindowRelayoutResult mRelayoutResult = new WindowRelayoutResult(
+ mWinFrames, mMergedConfiguration, mSurfaceControl, mInsetsState, mTempControls);
private final Point mSurfaceSize = new Point();
private final Point mLastSurfaceSize = new Point();
@@ -1277,15 +1273,8 @@
} else {
mLayout.surfaceInsets.set(0, 0, 0, 0);
}
- final int relayoutResult;
- if (windowSessionRelayoutInfo()) {
- relayoutResult = mSession.relayout(mWindow, mLayout, mWidth, mHeight,
- View.VISIBLE, 0, 0, 0, mRelayoutResult);
- } else {
- relayoutResult = mSession.relayoutLegacy(mWindow, mLayout, mWidth, mHeight,
- View.VISIBLE, 0, 0, 0, mWinFrames, mMergedConfiguration,
- mSurfaceControl, mInsetsState, mTempControls, mSyncSeqIdBundle);
- }
+ final int relayoutResult = mSession.relayout(mWindow, mLayout, mWidth, mHeight,
+ View.VISIBLE, 0, 0, 0, mRelayoutResult);
final Rect outMaxBounds = mMergedConfiguration.getMergedConfiguration()
.windowConfiguration.getMaxBounds();
if (!outMaxBounds.equals(maxBounds)) {
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index e3e4fc0..070d33b 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -49,18 +49,6 @@
*/
interface IWindowSession {
- /**
- * Bundle key to store the latest sync seq id for the relayout configuration.
- * @see #relayout
- */
- const String KEY_RELAYOUT_BUNDLE_SEQID = "seqid";
- /**
- * Bundle key to store the latest ActivityWindowInfo associated with the relayout configuration.
- * Will only be set if the relayout window is an activity window.
- * @see #relayout
- */
- const String KEY_RELAYOUT_BUNDLE_ACTIVITY_WINDOW_INFO = "activity_window_info";
-
int addToDisplay(IWindow window, in WindowManager.LayoutParams attrs,
in int viewVisibility, in int layerStackId, int requestedVisibleTypes,
out InputChannel outInputChannel, out InsetsState insetsState,
@@ -85,16 +73,6 @@
void remove(IBinder clientToken);
/**
- * @deprecated
- */
- int relayoutLegacy(IWindow window, in WindowManager.LayoutParams attrs,
- int requestedWidth, int requestedHeight, int viewVisibility,
- int flags, int seq, int lastSyncSeqId, out ClientWindowFrames outFrames,
- out MergedConfiguration outMergedConfiguration, out SurfaceControl outSurfaceControl,
- out InsetsState insetsState, out InsetsSourceControl.Array activeControls,
- out Bundle bundle);
-
- /**
* Change the parameters of a window. You supply the
* new parameters, it returns the new frame of the window on screen (the
* position should be ignored) and surface of the window. The surface
diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java
index 79a9f2d..72d2d3b 100644
--- a/core/java/android/view/MotionEvent.java
+++ b/core/java/android/view/MotionEvent.java
@@ -16,15 +16,6 @@
package android.view;
-import static android.os.IInputConstants.INPUT_EVENT_FLAG_CANCELED;
-import static android.os.IInputConstants.MOTION_EVENT_FLAG_HOVER_EXIT_PENDING;
-import static android.os.IInputConstants.INPUT_EVENT_FLAG_IS_ACCESSIBILITY_EVENT;
-import static android.os.IInputConstants.MOTION_EVENT_FLAG_IS_GENERATED_GESTURE;
-import static android.os.IInputConstants.MOTION_EVENT_FLAG_NO_FOCUS_CHANGE;
-import static android.os.IInputConstants.INPUT_EVENT_FLAG_TAINTED;
-import static android.os.IInputConstants.MOTION_EVENT_FLAG_TARGET_ACCESSIBILITY_FOCUS;
-import static android.os.IInputConstants.MOTION_EVENT_FLAG_WINDOW_IS_OBSCURED;
-import static android.os.IInputConstants.MOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED;
import static android.view.Display.DEFAULT_DISPLAY;
import static java.lang.annotation.RetentionPolicy.SOURCE;
@@ -38,6 +29,7 @@
import android.compat.annotation.UnsupportedAppUsage;
import android.graphics.Matrix;
import android.os.Build;
+import android.os.MotionEventFlag;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.SystemClock;
@@ -476,7 +468,7 @@
* to drop the suspect touches or to take additional precautions to confirm the user's
* actual intent.
*/
- public static final int FLAG_WINDOW_IS_OBSCURED = MOTION_EVENT_FLAG_WINDOW_IS_OBSCURED;
+ public static final int FLAG_WINDOW_IS_OBSCURED = MotionEventFlag.WINDOW_IS_OBSCURED;
/**
* This flag indicates that the window that received this motion event is partly
@@ -493,7 +485,7 @@
* obstructed in areas other than the touched location.
*/
public static final int FLAG_WINDOW_IS_PARTIALLY_OBSCURED =
- MOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED;
+ MotionEventFlag.WINDOW_IS_PARTIALLY_OBSCURED;
/**
* This private flag is only set on {@link #ACTION_HOVER_MOVE} events and indicates that
@@ -501,7 +493,7 @@
* prevent generating redundant {@link #ACTION_HOVER_ENTER} events.
* @hide
*/
- public static final int FLAG_HOVER_EXIT_PENDING = MOTION_EVENT_FLAG_HOVER_EXIT_PENDING;
+ public static final int FLAG_HOVER_EXIT_PENDING = MotionEventFlag.HOVER_EXIT_PENDING;
/**
* This flag indicates that the event has been generated by a gesture generator. It
@@ -509,7 +501,7 @@
*
* @hide
*/
- public static final int FLAG_IS_GENERATED_GESTURE = MOTION_EVENT_FLAG_IS_GENERATED_GESTURE;
+ public static final int FLAG_IS_GENERATED_GESTURE = MotionEventFlag.IS_GENERATED_GESTURE;
/**
* This flag is only set for events with {@link #ACTION_POINTER_UP} and {@link #ACTION_CANCEL}.
@@ -522,7 +514,7 @@
* @see #ACTION_POINTER_UP
* @see #ACTION_CANCEL
*/
- public static final int FLAG_CANCELED = INPUT_EVENT_FLAG_CANCELED;
+ public static final int FLAG_CANCELED = MotionEventFlag.CANCELED;
/**
* This flag indicates that the event will not cause a focus change if it is directed to an
@@ -531,7 +523,7 @@
* window into focus.
* @hide
*/
- public static final int FLAG_NO_FOCUS_CHANGE = MOTION_EVENT_FLAG_NO_FOCUS_CHANGE;
+ public static final int FLAG_NO_FOCUS_CHANGE = MotionEventFlag.NO_FOCUS_CHANGE;
/**
* This flag indicates that this event was modified by or generated from an accessibility
@@ -539,7 +531,7 @@
* @hide
*/
@TestApi
- public static final int FLAG_IS_ACCESSIBILITY_EVENT = INPUT_EVENT_FLAG_IS_ACCESSIBILITY_EVENT;
+ public static final int FLAG_IS_ACCESSIBILITY_EVENT = MotionEventFlag.IS_ACCESSIBILITY_EVENT;
/**
* Private flag that indicates when the system has detected that this motion event
@@ -550,7 +542,7 @@
* @see #isTainted
* @see #setTainted
*/
- public static final int FLAG_TAINTED = INPUT_EVENT_FLAG_TAINTED;
+ public static final int FLAG_TAINTED = MotionEventFlag.TAINTED;
/**
* Private flag indicating that this event was synthesized by the system and should be delivered
@@ -566,7 +558,7 @@
* @see #setTargetAccessibilityFocus(boolean)
*/
public static final int FLAG_TARGET_ACCESSIBILITY_FOCUS =
- MOTION_EVENT_FLAG_TARGET_ACCESSIBILITY_FOCUS;
+ MotionEventFlag.TARGET_ACCESSIBILITY_FOCUS;
/** @hide */
@IntDef(flag = true, prefix = { "FLAG_" }, value = {
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 9f4d7e2..1494d21 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -25,8 +25,6 @@
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;
import static android.view.DragEvent.ACTION_DRAG_LOCATION;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_APP_PROGRESS_GENERATION_ALLOWED;
-import static android.view.flags.Flags.sensitiveContentPrematureProtectionRemovedFix;
import static android.view.InputDevice.SOURCE_CLASS_NONE;
import static android.view.InsetsSource.ID_IME;
import static android.view.Surface.FRAME_RATE_CATEGORY_DEFAULT;
@@ -90,6 +88,7 @@
import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_APP_PROGRESS_GENERATION_ALLOWED;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_EDGE_TO_EDGE_ENFORCED;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FIT_INSETS_CONTROLLED;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY;
@@ -114,6 +113,7 @@
import static android.view.accessibility.Flags.reduceWindowContentChangedEventThrottle;
import static android.view.flags.Flags.addSchandleToVriSurface;
import static android.view.flags.Flags.sensitiveContentAppProtection;
+import static android.view.flags.Flags.sensitiveContentPrematureProtectionRemovedFix;
import static android.view.flags.Flags.toolkitFrameRateFunctionEnablingReadOnly;
import static android.view.flags.Flags.toolkitFrameRateTypingReadOnly;
import static android.view.flags.Flags.toolkitFrameRateVelocityMappingReadOnly;
@@ -124,12 +124,11 @@
import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.INSETS_CONTROLLER;
import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
+import static com.android.text.flags.Flags.disableHandwritingInitiatorForIme;
import static com.android.window.flags.Flags.activityWindowInfoFlag;
import static com.android.window.flags.Flags.enableBufferTransformHintFromDisplay;
import static com.android.window.flags.Flags.insetsControlChangedItem;
import static com.android.window.flags.Flags.setScPropertiesInClient;
-import static com.android.window.flags.Flags.windowSessionRelayoutInfo;
-import static com.android.text.flags.Flags.disableHandwritingInitiatorForIme;
import android.Manifest;
import android.accessibilityservice.AccessibilityService;
@@ -179,7 +178,6 @@
import android.graphics.RenderNode;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
-import android.hardware.SyncFence;
import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManager.DisplayListener;
import android.hardware.display.DisplayManagerGlobal;
@@ -222,7 +220,6 @@
import android.view.InputDevice.InputSourceClass;
import android.view.Surface.OutOfResourcesException;
import android.view.SurfaceControl.Transaction;
-import android.view.SurfaceControl.TransactionStats;
import android.view.View.AttachInfo;
import android.view.View.FocusDirection;
import android.view.View.MeasureSpec;
@@ -298,7 +295,6 @@
import java.util.Queue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
-import java.util.function.Consumer;
import java.util.function.Predicate;
/**
* The top of a view hierarchy, implementing the needed protocol between View
@@ -1138,7 +1134,7 @@
*/
/**
- * A temporary object used so relayoutWindow can return the latest SyncSeqId
+ * Object for relayoutWindow to return the latest window info, including the SyncSeqId
* system. The SyncSeqId system was designed to work without synchronous relayout
* window, and actually synchronous relayout window presents a problem. We could have
* a sequence like this:
@@ -1152,14 +1148,8 @@
* we get rid of synchronous relayout, until then, we use this bundle to channel the
* integer back over relayout.
*/
- private final Bundle mRelayoutBundle = windowSessionRelayoutInfo()
- ? null
- : new Bundle();
-
- private final WindowRelayoutResult mRelayoutResult = windowSessionRelayoutInfo()
- ? new WindowRelayoutResult(mTmpFrames, mPendingMergedConfiguration, mSurfaceControl,
- mTempInsets, mTempControls)
- : null;
+ private final WindowRelayoutResult mRelayoutResult = new WindowRelayoutResult(
+ mTmpFrames, mPendingMergedConfiguration, mSurfaceControl, mTempInsets, mTempControls);
private static volatile boolean sAnrReported = false;
static BLASTBufferQueue.TransactionHangCallback sTransactionHangCallback =
@@ -1195,13 +1185,6 @@
private String mFpsTraceName;
private String mLargestViewTraceName;
- private final boolean mAppStartInfoTimestampsFlagValue;
- @GuardedBy("this")
- private boolean mAppStartTimestampsSent = false;
- private boolean mAppStartTrackingStarted = false;
- private long mRenderThreadDrawStartTimeNs = -1;
- private long mFirstFramePresentedTimeNs = -1;
-
private static boolean sToolkitSetFrameRateReadOnlyFlagValue;
private static boolean sToolkitFrameRateFunctionEnablingReadOnlyFlagValue;
private static boolean sToolkitMetricsForFrameRateDecisionFlagValue;
@@ -1319,8 +1302,6 @@
} else {
mSensitiveContentProtectionService = null;
}
-
- mAppStartInfoTimestampsFlagValue = android.app.Flags.appStartInfoTimestamps();
}
public static void addFirstDrawHandler(Runnable callback) {
@@ -2596,12 +2577,6 @@
notifySurfaceDestroyed();
}
destroySurface();
-
- // Reset so they can be sent again for warm starts.
- mAppStartTimestampsSent = false;
- mAppStartTrackingStarted = false;
- mRenderThreadDrawStartTimeNs = -1;
- mFirstFramePresentedTimeNs = -1;
}
}
}
@@ -4400,30 +4375,6 @@
reportDrawFinished(t, seqId);
}
});
-
- // Only trigger once per {@link ViewRootImpl} instance, so don't add listener if
- // {link mTransactionCompletedTimeNs} has already been set.
- if (mAppStartInfoTimestampsFlagValue && !mAppStartTrackingStarted) {
- mAppStartTrackingStarted = true;
- Transaction transaction = new Transaction();
- transaction.addTransactionCompletedListener(mExecutor,
- new Consumer<TransactionStats>() {
- @Override
- public void accept(TransactionStats transactionStats) {
- SyncFence presentFence = transactionStats.getPresentFence();
- if (presentFence.awaitForever()) {
- if (mFirstFramePresentedTimeNs == -1) {
- // Only trigger once per {@link ViewRootImpl} instance.
- mFirstFramePresentedTimeNs = presentFence.getSignalTime();
- maybeSendAppStartTimes();
- }
- }
- presentFence.close();
- }
- });
- applyTransactionOnDraw(transaction);
- }
-
if (DEBUG_BLAST) {
Log.d(mTag, "Setup new sync=" + mWmsRequestSyncGroup.getName());
}
@@ -4431,45 +4382,6 @@
mWmsRequestSyncGroup.add(this, null /* runnable */);
}
- private void maybeSendAppStartTimes() {
- synchronized (this) {
- if (mAppStartTimestampsSent) {
- // Don't send timestamps more than once.
- return;
- }
-
- // If we already have {@link mRenderThreadDrawStartTimeNs} then pass it through, if not
- // post to main thread and check if we have it there.
- if (mRenderThreadDrawStartTimeNs != -1) {
- sendAppStartTimesLocked();
- } else {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- synchronized (ViewRootImpl.this) {
- if (mRenderThreadDrawStartTimeNs == -1) {
- return;
- }
- sendAppStartTimesLocked();
- }
- }
- });
- }
- }
- }
-
- @GuardedBy("this")
- private void sendAppStartTimesLocked() {
- try {
- ActivityManager.getService().reportStartInfoViewTimestamps(
- mRenderThreadDrawStartTimeNs, mFirstFramePresentedTimeNs);
- mAppStartTimestampsSent = true;
- } catch (RemoteException e) {
- // Ignore, timestamps may be lost.
- if (DBG) Log.d(TAG, "Exception attempting to report start timestamps.", e);
- }
- }
-
/**
* Helper used to notify the service to block projection when a sensitive
* view (the view displays sensitive content) is attached to the window.
@@ -5656,13 +5568,7 @@
registerCallbackForPendingTransactions();
}
- long timeNs = SystemClock.uptimeNanos();
mAttachInfo.mThreadedRenderer.draw(mView, mAttachInfo, this);
-
- // Only trigger once per {@link ViewRootImpl} instance.
- if (mAppStartInfoTimestampsFlagValue && mRenderThreadDrawStartTimeNs == -1) {
- mRenderThreadDrawStartTimeNs = timeNs;
- }
} else {
// If we get here with a disabled & requested hardware renderer, something went
// wrong (an invalidate posted right before we destroyed the hardware surface
@@ -9261,42 +9167,19 @@
insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0, mRelayoutSeq,
mLastSyncSeqId);
} else {
- if (windowSessionRelayoutInfo()) {
- relayoutResult = mWindowSession.relayout(mWindow, params,
- requestedWidth, requestedHeight, viewVisibility,
- insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0,
- mRelayoutSeq, mLastSyncSeqId, mRelayoutResult);
- } else {
- relayoutResult = mWindowSession.relayoutLegacy(mWindow, params,
- requestedWidth, requestedHeight, viewVisibility,
- insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0,
- mRelayoutSeq, mLastSyncSeqId, mTmpFrames, mPendingMergedConfiguration,
- mSurfaceControl, mTempInsets, mTempControls, mRelayoutBundle);
- }
+ relayoutResult = mWindowSession.relayout(mWindow, params,
+ requestedWidth, requestedHeight, viewVisibility,
+ insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0,
+ mRelayoutSeq, mLastSyncSeqId, mRelayoutResult);
mRelayoutRequested = true;
if (activityWindowInfoFlag() && mPendingActivityWindowInfo != null) {
- ActivityWindowInfo outInfo = null;
- if (windowSessionRelayoutInfo()) {
- outInfo = mRelayoutResult != null ? mRelayoutResult.activityWindowInfo : null;
- } else {
- try {
- outInfo = mRelayoutBundle.getParcelable(
- IWindowSession.KEY_RELAYOUT_BUNDLE_ACTIVITY_WINDOW_INFO,
- ActivityWindowInfo.class);
- mRelayoutBundle.remove(
- IWindowSession.KEY_RELAYOUT_BUNDLE_ACTIVITY_WINDOW_INFO);
- } catch (IllegalStateException e) {
- Log.e(TAG, "Failed to get ActivityWindowInfo from relayout Bundle", e);
- }
- }
+ final ActivityWindowInfo outInfo = mRelayoutResult.activityWindowInfo;
if (outInfo != null) {
mPendingActivityWindowInfo.set(outInfo);
}
}
- final int maybeSyncSeqId = windowSessionRelayoutInfo()
- ? mRelayoutResult.syncSeqId
- : mRelayoutBundle.getInt(IWindowSession.KEY_RELAYOUT_BUNDLE_SEQID);
+ final int maybeSyncSeqId = mRelayoutResult.syncSeqId;
if (maybeSyncSeqId > 0) {
mSyncSeqId = maybeSyncSeqId;
}
diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java
index d7d764b..55f22a6 100644
--- a/core/java/android/view/WindowlessWindowManager.java
+++ b/core/java/android/view/WindowlessWindowManager.java
@@ -23,7 +23,6 @@
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.Region;
-import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteCallback;
import android.os.RemoteException;
@@ -349,18 +348,6 @@
}
@Override
- public int relayoutLegacy(IWindow window, WindowManager.LayoutParams inAttrs,
- int requestedWidth, int requestedHeight, int viewFlags, int flags, int seq,
- int lastSyncSeqId, ClientWindowFrames outFrames,
- MergedConfiguration outMergedConfiguration, SurfaceControl outSurfaceControl,
- InsetsState outInsetsState, InsetsSourceControl.Array outActiveControls,
- Bundle outSyncSeqIdBundle) {
- return relayoutInner(window, inAttrs, requestedWidth, requestedHeight, viewFlags, flags,
- seq, lastSyncSeqId, outFrames, outMergedConfiguration, outSurfaceControl,
- outInsetsState, outActiveControls);
- }
-
- @Override
public int relayout(IWindow window, WindowManager.LayoutParams inAttrs,
int requestedWidth, int requestedHeight, int viewFlags, int flags, int seq,
int lastSyncSeqId, WindowRelayoutResult outRelayoutResult) {
diff --git a/core/java/android/view/accessibility/a11ychecker/AccessibilityNodePathBuilder.java b/core/java/android/view/accessibility/a11ychecker/AccessibilityNodePathBuilder.java
new file mode 100644
index 0000000..2996dde
--- /dev/null
+++ b/core/java/android/view/accessibility/a11ychecker/AccessibilityNodePathBuilder.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.accessibility.a11ychecker;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.view.accessibility.AccessibilityNodeInfo;
+
+/**
+ * Utility class to create developer-friendly {@link AccessibilityNodeInfo} path Strings for use
+ * in reporting AccessibilityCheck results.
+ *
+ * @hide
+ */
+public final class AccessibilityNodePathBuilder {
+
+ /**
+ * Returns the path of the node within its accessibility hierarchy starting from the root node
+ * down to the given node itself, and prefixed by the package name. This path is not guaranteed
+ * to be unique. This can return null in case the node's hierarchy changes while scanning.
+ *
+ * <p>Each element in the path is represented by its View ID resource name, when available, or
+ * the
+ * simple class name if not. The path also includes the index of each child node relative to
+ * its
+ * parent. See {@link AccessibilityNodeInfo#getViewIdResourceName()}.
+ *
+ * <p>For example,
+ * "com.example.app:RootElementClassName/parent_resource_name[1]/TargetElementClassName[3]"
+ * indicates the element has type {@code TargetElementClassName}, and is the third child of an
+ * element with the resource name {@code parent_resource_name}, which is the first child of an
+ * element of type {@code RootElementClassName}.
+ *
+ * <p>This format is consistent with elements paths in Pre-Launch Reports and the Accessibility
+ * Scanner, starting from the window's root node instead of the first resource name.
+ * TODO (b/344607035): link to ClusteringUtils when AATF is merged in main.
+ */
+ public static @Nullable String createNodePath(@NonNull AccessibilityNodeInfo nodeInfo) {
+ StringBuilder resourceIdBuilder = getNodePathBuilder(nodeInfo);
+ return resourceIdBuilder == null ? null : String.valueOf(nodeInfo.getPackageName()) + ':'
+ + resourceIdBuilder;
+ }
+
+ private static @Nullable StringBuilder getNodePathBuilder(AccessibilityNodeInfo nodeInfo) {
+ AccessibilityNodeInfo parent = nodeInfo.getParent();
+ if (parent == null) {
+ return new StringBuilder(getShortUiElementName(nodeInfo));
+ }
+ StringBuilder parentNodePath = getNodePathBuilder(parent);
+ if (parentNodePath == null) {
+ return null;
+ }
+ int childCount = parent.getChildCount();
+ for (int i = 0; i < childCount; i++) {
+ if (!nodeInfo.equals(parent.getChild(i))) {
+ continue;
+ }
+ CharSequence uiElementName = getShortUiElementName(nodeInfo);
+ if (uiElementName != null) {
+ parentNodePath.append('/').append(uiElementName).append('[').append(i + 1).append(
+ ']');
+ } else {
+ parentNodePath.append(":nth-child(").append(i + 1).append(')');
+ }
+ return parentNodePath;
+ }
+ return null;
+ }
+
+ //Returns the part of the element's View ID resource name after the qualifier
+ // "package_name:id/" or the last '/', when available. Otherwise, returns the element's
+ // simple class name.
+ private static CharSequence getShortUiElementName(AccessibilityNodeInfo nodeInfo) {
+ String viewIdResourceName = nodeInfo.getViewIdResourceName();
+ if (viewIdResourceName != null) {
+ String idQualifier = ":id/";
+ int idQualifierStartIndex = viewIdResourceName.indexOf(idQualifier);
+ int unqualifiedNameStartIndex = idQualifierStartIndex == -1 ? 0
+ : (idQualifierStartIndex + idQualifier.length());
+ return viewIdResourceName.substring(unqualifiedNameStartIndex);
+ }
+ return getSimpleClassName(nodeInfo);
+ }
+
+ private static CharSequence getSimpleClassName(AccessibilityNodeInfo nodeInfo) {
+ CharSequence name = nodeInfo.getClassName();
+ for (int i = name.length() - 1; i > 0; i--) {
+ char ithChar = name.charAt(i);
+ if (ithChar == '.' || ithChar == '$') {
+ return name.subSequence(i + 1, name.length());
+ }
+ }
+ return name;
+ }
+
+ private AccessibilityNodePathBuilder() {
+ }
+}
diff --git a/core/java/android/view/accessibility/a11ychecker/Android.bp b/core/java/android/view/accessibility/a11ychecker/Android.bp
new file mode 100644
index 0000000..e5a577c
--- /dev/null
+++ b/core/java/android/view/accessibility/a11ychecker/Android.bp
@@ -0,0 +1,7 @@
+java_library_static {
+ name: "A11yChecker",
+ srcs: [
+ "*.java",
+ ],
+ visibility: ["//visibility:public"],
+}
diff --git a/core/java/android/view/accessibility/a11ychecker/OWNERS b/core/java/android/view/accessibility/a11ychecker/OWNERS
new file mode 100644
index 0000000..d1e7986
--- /dev/null
+++ b/core/java/android/view/accessibility/a11ychecker/OWNERS
@@ -0,0 +1,4 @@
+# Android Accessibility Framework owners
+include /services/accessibility/OWNERS
+
+yaraabdullatif@google.com
diff --git a/core/java/android/view/accessibility/flags/accessibility_flags.aconfig b/core/java/android/view/accessibility/flags/accessibility_flags.aconfig
index 95d001f..d0bc57b 100644
--- a/core/java/android/view/accessibility/flags/accessibility_flags.aconfig
+++ b/core/java/android/view/accessibility/flags/accessibility_flags.aconfig
@@ -100,6 +100,20 @@
flag {
namespace: "accessibility"
+ name: "global_action_menu"
+ description: "Allow AccessibilityService to perform GLOBAL_ACTION_MENU"
+ bug: "334954140"
+}
+
+flag {
+ namespace: "accessibility"
+ name: "global_action_media_play_pause"
+ description: "Allow AccessibilityService to perform GLOBAL_ACTION_MEDIA_PLAY_PAUSE"
+ bug: "334954140"
+}
+
+flag {
+ namespace: "accessibility"
name: "granular_scrolling"
is_exported: true
description: "Allow the use of granular scrolling. This allows scrollable nodes to scroll by increments other than a full screen"
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 3c5623f..9896d98 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -17,8 +17,10 @@
package android.widget;
import static android.appwidget.flags.Flags.FLAG_DRAW_DATA_PARCEL;
+import static android.appwidget.flags.Flags.FLAG_REMOTE_VIEWS_PROTO;
import static android.appwidget.flags.Flags.drawDataParcel;
import static android.appwidget.flags.Flags.remoteAdapterConversion;
+import static android.util.proto.ProtoInputStream.NO_MORE_FIELDS;
import static android.view.inputmethod.Flags.FLAG_HOME_SCREEN_HANDWRITING_DELEGATOR;
import android.annotation.AttrRes;
@@ -94,6 +96,9 @@
import android.util.SparseIntArray;
import android.util.TypedValue;
import android.util.TypedValue.ComplexDimensionUnit;
+import android.util.proto.ProtoInputStream;
+import android.util.proto.ProtoOutputStream;
+import android.util.proto.ProtoUtils;
import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
import android.view.LayoutInflater.Filter;
@@ -7822,4 +7827,278 @@
mClassCookies = classCookies;
}
}
+
+ /**
+ * Write this RemoteViews to proto.
+ * @hide
+ */
+ @FlaggedApi(FLAG_REMOTE_VIEWS_PROTO)
+ public void writePreviewToProto(@NonNull Context context, @NonNull ProtoOutputStream out) {
+ if (mApplication != null) {
+ // mApplication may be null if this was created with DrawInstructions constructor.
+ out.write(RemoteViewsProto.PACKAGE_NAME, mApplication.packageName);
+ }
+ Resources appResources = getContextForResourcesEnsuringCorrectCachedApkPaths(
+ context).getResources();
+ if (mLayoutId != 0) {
+ out.write(RemoteViewsProto.LAYOUT_ID, appResources.getResourceName(mLayoutId));
+ }
+ if (mLightBackgroundLayoutId != 0) {
+ out.write(RemoteViewsProto.LIGHT_BACKGROUND_LAYOUT_ID,
+ appResources.getResourceName(mLightBackgroundLayoutId));
+ }
+ if (mViewId != 0 && mViewId != -1) {
+ out.write(RemoteViewsProto.VIEW_ID, appResources.getResourceName(mViewId));
+ }
+ out.write(RemoteViewsProto.IS_ROOT, mIsRoot);
+ out.write(RemoteViewsProto.APPLY_FLAGS, mApplyFlags);
+ out.write(RemoteViewsProto.HAS_DRAW_INSTRUCTIONS, mHasDrawInstructions);
+ if (mProviderInstanceId != -1) {
+ out.write(RemoteViewsProto.PROVIDER_INSTANCE_ID, mProviderInstanceId);
+ }
+
+ if (!hasMultipleLayouts()) {
+ out.write(RemoteViewsProto.MODE, MODE_NORMAL);
+ if (mIdealSize != null) {
+ final long token = out.start(RemoteViewsProto.IDEAL_SIZE);
+ out.write(SizeFProto.WIDTH, mIdealSize.getWidth());
+ out.write(SizeFProto.HEIGHT, mIdealSize.getHeight());
+ out.end(token);
+ }
+ } else if (hasSizedRemoteViews()) {
+ out.write(RemoteViewsProto.MODE, MODE_HAS_SIZED_REMOTEVIEWS);
+ for (RemoteViews view : mSizedRemoteViews) {
+ final long sizedViewToken = out.start(RemoteViewsProto.SIZED_REMOTEVIEWS);
+ view.writePreviewToProto(context, out);
+ out.end(sizedViewToken);
+ }
+ } else {
+ out.write(RemoteViewsProto.MODE, MODE_HAS_LANDSCAPE_AND_PORTRAIT);
+ final long landscapeViewToken = out.start(RemoteViewsProto.LANDSCAPE_REMOTEVIEWS);
+ mLandscape.writePreviewToProto(context, out);
+ out.end(landscapeViewToken);
+ final long portraitViewToken = out.start(RemoteViewsProto.PORTRAIT_REMOTEVIEWS);
+ mPortrait.writePreviewToProto(context, out);
+ out.end(portraitViewToken);
+ }
+ }
+
+ /**
+ * Create a RemoteViews from proto input.
+ * @hide
+ */
+ @FlaggedApi(FLAG_REMOTE_VIEWS_PROTO)
+ public static RemoteViews createPreviewFromProto(Context context, ProtoInputStream in)
+ throws Exception {
+ return createFromProto(in).create(context, context.getResources(), /* rootData= */ null,
+ /* depth= */ 0);
+ }
+
+ private static PendingResources<RemoteViews> createFromProto(ProtoInputStream in)
+ throws Exception {
+ // Grouping these variables into an anonymous object allows us to access them through `ref`
+ // (which is final) later in the lambda.
+ final var ref = new Object() {
+ final RemoteViews mRv = new RemoteViews();
+ int mMode = 0;
+ int mApplyFlags = 0;
+ long mProviderInstanceId = -1;
+ String mPackageName = null;
+ SizeF mIdealSize = null;
+ String mLayoutResName = null;
+ String mLightBackgroundResName = null;
+ String mViewResName = null;
+ final List<PendingResources<RemoteViews>> mSizedRemoteViews = new ArrayList<>();
+ PendingResources<RemoteViews> mLandscapeViews = null;
+ PendingResources<RemoteViews> mPortraitViews = null;
+ boolean mIsRoot = false;
+ boolean mHasDrawInstructions = false;
+ };
+
+ try {
+ while (in.nextField() != NO_MORE_FIELDS) {
+ switch (in.getFieldNumber()) {
+ case (int) RemoteViewsProto.MODE:
+ ref.mMode = in.readInt(RemoteViewsProto.MODE);
+ break;
+ case (int) RemoteViewsProto.PACKAGE_NAME:
+ ref.mPackageName = in.readString(RemoteViewsProto.PACKAGE_NAME);
+ break;
+ case (int) RemoteViewsProto.IDEAL_SIZE:
+ final long idealSizeToken = in.start(RemoteViewsProto.IDEAL_SIZE);
+ ref.mIdealSize = createSizeFFromProto(in);
+ in.end(idealSizeToken);
+ break;
+ case (int) RemoteViewsProto.LAYOUT_ID:
+ ref.mLayoutResName = in.readString(RemoteViewsProto.LAYOUT_ID);
+ break;
+ case (int) RemoteViewsProto.LIGHT_BACKGROUND_LAYOUT_ID:
+ ref.mLightBackgroundResName = in.readString(
+ RemoteViewsProto.LIGHT_BACKGROUND_LAYOUT_ID);
+ break;
+ case (int) RemoteViewsProto.VIEW_ID:
+ ref.mViewResName = in.readString(RemoteViewsProto.VIEW_ID);
+ break;
+ case (int) RemoteViewsProto.APPLY_FLAGS:
+ ref.mApplyFlags = in.readInt(RemoteViewsProto.APPLY_FLAGS);
+ break;
+ case (int) RemoteViewsProto.PROVIDER_INSTANCE_ID:
+ ref.mProviderInstanceId = in.readInt(RemoteViewsProto.PROVIDER_INSTANCE_ID);
+ break;
+ case (int) RemoteViewsProto.SIZED_REMOTEVIEWS:
+ final long sizedToken = in.start(RemoteViewsProto.SIZED_REMOTEVIEWS);
+ ref.mSizedRemoteViews.add(createFromProto(in));
+ in.end(sizedToken);
+ break;
+ case (int) RemoteViewsProto.LANDSCAPE_REMOTEVIEWS:
+ final long landscapeToken = in.start(
+ RemoteViewsProto.LANDSCAPE_REMOTEVIEWS);
+ ref.mLandscapeViews = createFromProto(in);
+ in.end(landscapeToken);
+ break;
+ case (int) RemoteViewsProto.PORTRAIT_REMOTEVIEWS:
+ final long portraitToken = in.start(RemoteViewsProto.PORTRAIT_REMOTEVIEWS);
+ ref.mPortraitViews = createFromProto(in);
+ in.end(portraitToken);
+ break;
+ case (int) RemoteViewsProto.IS_ROOT:
+ ref.mIsRoot = in.readBoolean(RemoteViewsProto.IS_ROOT);
+ break;
+ case (int) RemoteViewsProto.HAS_DRAW_INSTRUCTIONS:
+ ref.mHasDrawInstructions = in.readBoolean(
+ RemoteViewsProto.HAS_DRAW_INSTRUCTIONS);
+ break;
+ default:
+ Log.w(LOG_TAG, "Unhandled field while reading RemoteViews proto!\n"
+ + ProtoUtils.currentFieldToString(in));
+ }
+ }
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+
+ return (context, resources, rootData, depth) -> {
+ if (depth > MAX_NESTED_VIEWS && (UserHandle.getAppId(Binder.getCallingUid())
+ != Process.SYSTEM_UID)) {
+ throw new IllegalArgumentException("Too many nested views.");
+ }
+ depth++;
+
+ RemoteViews rv = ref.mRv;
+ rv.mApplyFlags = ref.mApplyFlags;
+ rv.mIsRoot = ref.mIsRoot;
+ rv.mHasDrawInstructions = ref.mHasDrawInstructions;
+
+ // The root view will read its HierarchyRootData (bitmap cache, collection cache) from
+ // proto; all nested views will instead get it through the rootData parameter.
+ if (rootData == null) {
+ if (!rv.mIsRoot || depth != 1) {
+ throw new IllegalStateException(
+ "A nested view did not receive HierarchyRootData");
+ }
+ rootData = rv.getHierarchyRootData();
+ } else {
+ rv.configureAsChild(rootData);
+ }
+
+ Context appContext = null;
+ Resources appResources = null;
+ if (!ref.mHasDrawInstructions) {
+ checkProtoResultNotNull(ref.mPackageName, "No application info");
+ rv.mApplication = context.getPackageManager().getApplicationInfo(ref.mPackageName,
+ /* flags= */ 0);
+ appContext = rv.getContextForResourcesEnsuringCorrectCachedApkPaths(context);
+ appResources = appContext.getResources();
+
+ checkProtoResultNotNull(ref.mLayoutResName, "No layout id");
+ rv.mLayoutId = appResources.getIdentifier(ref.mLayoutResName, /* defType= */ null,
+ /* defPackage= */ null);
+ checkValidResource(rv.mLayoutId, "Invalid layout id", ref.mLayoutResName);
+
+ if (ref.mViewResName != null) {
+ rv.mViewId = appResources.getIdentifier(ref.mViewResName, /* defType= */ null,
+ /* defPackage= */ null);
+ checkValidResource(rv.mViewId, "Invalid view id", ref.mViewResName);
+ }
+
+ if (ref.mLightBackgroundResName != null) {
+ int lightBackgroundLayoutId = appResources.getIdentifier(
+ ref.mLightBackgroundResName,
+ /* defType= */ null, /* defPackage= */ null);
+ checkValidResource(lightBackgroundLayoutId,
+ "Invalid light background layout id", ref.mLightBackgroundResName);
+ rv.setLightBackgroundLayoutId(lightBackgroundLayoutId);
+ }
+ }
+ if (ref.mProviderInstanceId != -1) {
+ rv.mProviderInstanceId = ref.mProviderInstanceId;
+ }
+ if (ref.mMode == MODE_NORMAL) {
+ rv.setIdealSize(ref.mIdealSize);
+ return rv;
+ } else if (ref.mMode == MODE_HAS_SIZED_REMOTEVIEWS) {
+ List<RemoteViews> sizedViews = new ArrayList<>();
+ for (RemoteViews.PendingResources<RemoteViews> pendingViews :
+ ref.mSizedRemoteViews) {
+ RemoteViews views = pendingViews.create(context, resources, rootData, depth);
+ sizedViews.add(views);
+ }
+ rv.initializeSizedRemoteViews(sizedViews.iterator());
+ return rv;
+ } else if (ref.mMode == MODE_HAS_LANDSCAPE_AND_PORTRAIT) {
+ checkProtoResultNotNull(ref.mLandscapeViews, "Missing landscape views");
+ checkProtoResultNotNull(ref.mPortraitViews, "Missing portrait views");
+ RemoteViews parentRv = new RemoteViews(
+ ref.mLandscapeViews.create(context, resources, rootData, depth),
+ ref.mPortraitViews.create(context, resources, rootData, depth));
+ parentRv.initializeFrom(/* src= */ rv, /* hierarchyRoot= */ rv);
+ return parentRv;
+ } else {
+ throw new InvalidProtoException(ref.mMode + " is not a valid mode.");
+ }
+ };
+ }
+
+ private static class InvalidProtoException extends Exception {
+ InvalidProtoException(String message) {
+ super(message);
+ }
+ }
+
+ private interface PendingResources<T> {
+ T create(Context context, Resources appResources, HierarchyRootData rootData, int depth)
+ throws Exception;
+ }
+
+ private static void checkValidResource(int id, String message, String resName)
+ throws Exception {
+ if (id == 0) throw new Exception(message + ": " + resName);
+ }
+
+ private static void checkProtoResultNotNull(Object o, String message)
+ throws InvalidProtoException {
+ if (o == null) {
+ throw new InvalidProtoException(message);
+ }
+ }
+
+ private static SizeF createSizeFFromProto(ProtoInputStream in) throws Exception {
+ float width = 0;
+ float height = 0;
+ while (in.nextField() != NO_MORE_FIELDS) {
+ switch (in.getFieldNumber()) {
+ case (int) SizeFProto.WIDTH:
+ width = in.readFloat(SizeFProto.WIDTH);
+ break;
+ case (int) SizeFProto.HEIGHT:
+ height = in.readFloat(SizeFProto.HEIGHT);
+ break;
+ default:
+ Log.w(LOG_TAG, "Unhandled field while reading SizeF proto!\n"
+ + ProtoUtils.currentFieldToString(in));
+ }
+ }
+
+ return new SizeF(width, height);
+ }
}
diff --git a/core/java/android/window/WindowTokenClient.java b/core/java/android/window/WindowTokenClient.java
index cc54a93..15adc80 100644
--- a/core/java/android/window/WindowTokenClient.java
+++ b/core/java/android/window/WindowTokenClient.java
@@ -19,8 +19,6 @@
import static android.window.ConfigurationHelper.isDifferentDisplay;
import static android.window.ConfigurationHelper.shouldUpdateResources;
-import static com.android.window.flags.Flags.windowTokenConfigThreadSafe;
-
import android.annotation.AnyThread;
import android.annotation.MainThread;
import android.annotation.NonNull;
@@ -146,7 +144,7 @@
if (context == null) {
return;
}
- if (shouldReportConfigChange && windowTokenConfigThreadSafe()) {
+ if (shouldReportConfigChange) {
// Only report to ClientTransactionListenerController when shouldReportConfigChange.
final ClientTransactionListenerController controller =
getClientTransactionListenerController();
diff --git a/core/java/android/window/flags/OWNERS b/core/java/android/window/flags/OWNERS
index fd73d35..0472b6c4 100644
--- a/core/java/android/window/flags/OWNERS
+++ b/core/java/android/window/flags/OWNERS
@@ -1,3 +1,4 @@
per-file responsible_apis.aconfig = file:/BAL_OWNERS
per-file large_screen_experiences_app_compat.aconfig = file:/LSE_APP_COMPAT_OWNERS
per-file accessibility.aconfig = file:/core/java/android/view/accessibility/OWNERS
+per-file lse_desktop_experience.aconfig = file:/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/OWNERS
diff --git a/core/java/android/window/flags/lse_desktop_experience.aconfig b/core/java/android/window/flags/lse_desktop_experience.aconfig
index ca125da..d0ab674 100644
--- a/core/java/android/window/flags/lse_desktop_experience.aconfig
+++ b/core/java/android/window/flags/lse_desktop_experience.aconfig
@@ -120,3 +120,10 @@
description: "Whether to enable min/max window size constraints when resizing a window in desktop windowing mode"
bug: "327589741"
}
+
+flag {
+ name: "show_desktop_windowing_dev_option"
+ namespace: "lse_desktop_experience"
+ description: "Whether to show developer option for enabling desktop windowing mode"
+ bug: "348193756"
+}
diff --git a/core/java/android/window/flags/windowing_sdk.aconfig b/core/java/android/window/flags/windowing_sdk.aconfig
index 0a4762d..8cd2a3e 100644
--- a/core/java/android/window/flags/windowing_sdk.aconfig
+++ b/core/java/android/window/flags/windowing_sdk.aconfig
@@ -93,16 +93,6 @@
flag {
namespace: "windowing_sdk"
- name: "window_token_config_thread_safe"
- description: "Ensure the Configuration pre/post changed is thread safe"
- bug: "334285008"
- metadata {
- purpose: PURPOSE_BUGFIX
- }
-}
-
-flag {
- namespace: "windowing_sdk"
name: "always_defer_transition_when_apply_wct"
description: "Report error when defer transition fails when it should not"
bug: "335562144"
@@ -113,17 +103,6 @@
flag {
namespace: "windowing_sdk"
- name: "window_session_relayout_info"
- description: "Pass an out RelayoutInfo instead of Bundle to fix the Parcel recycle bug"
- bug: "335601427"
- is_fixed_read_only: true
- metadata {
- purpose: PURPOSE_BUGFIX
- }
-}
-
-flag {
- namespace: "windowing_sdk"
name: "fix_pip_restore_to_overlay"
description: "Restore exit-pip activity back to ActivityEmbedding overlay"
bug: "297887697"
@@ -191,3 +170,14 @@
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ namespace: "windowing_sdk"
+ name: "fix_no_container_update_without_resize"
+ description: "Fix the containers not being updated when the Task is brought to front and has the same configuration"
+ bug: "344721335"
+ is_fixed_read_only: true
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/core/java/com/android/internal/accessibility/dialog/AccessibilityButtonChooserActivity.java b/core/java/com/android/internal/accessibility/dialog/AccessibilityButtonChooserActivity.java
index fc3cd45..c8d6194 100644
--- a/core/java/com/android/internal/accessibility/dialog/AccessibilityButtonChooserActivity.java
+++ b/core/java/com/android/internal/accessibility/dialog/AccessibilityButtonChooserActivity.java
@@ -29,8 +29,6 @@
import android.content.ComponentName;
import android.os.Bundle;
import android.provider.Settings;
-import android.text.TextUtils;
-import android.view.View;
import android.view.accessibility.AccessibilityManager;
import android.widget.GridView;
import android.widget.TextView;
@@ -73,16 +71,11 @@
promptPrologue.setText(isTouchExploreOn
? R.string.accessibility_gesture_3finger_prompt_text
: R.string.accessibility_gesture_prompt_text);
- }
- if (TextUtils.isEmpty(component)) {
final TextView prompt = findViewById(R.id.accessibility_button_prompt);
- if (isGestureNavigateEnabled) {
- prompt.setText(isTouchExploreOn
- ? R.string.accessibility_gesture_3finger_instructional_text
- : R.string.accessibility_gesture_instructional_text);
- }
- prompt.setVisibility(View.VISIBLE);
+ prompt.setText(isTouchExploreOn
+ ? R.string.accessibility_gesture_3finger_instructional_text
+ : R.string.accessibility_gesture_instructional_text);
}
mTargets.addAll(getTargets(this, SOFTWARE));
diff --git a/core/java/com/android/internal/compat/ChangeReporter.java b/core/java/com/android/internal/compat/ChangeReporter.java
index ded142c..f611571 100644
--- a/core/java/com/android/internal/compat/ChangeReporter.java
+++ b/core/java/com/android/internal/compat/ChangeReporter.java
@@ -42,7 +42,7 @@
*
* @hide
*/
-public final class ChangeReporter {
+public class ChangeReporter {
private static final String TAG = "CompatChangeReporter";
private static final Function<Integer, Set<ChangeReport>> NEW_CHANGE_REPORT_SET =
uid -> Collections.synchronizedSet(new HashSet<>());
@@ -88,17 +88,20 @@
* Report the change to stats log and to the debug log if the change was not previously
* logged already.
*
- * @param uid affected by the change
- * @param changeId the reported change id
- * @param state of the reported change - enabled/disabled/only logged
- * @param isLoggableBySdk whether debug logging is allowed for this change based on target
- * SDK version. This is combined with other logic to determine whether to
- * actually log. If the sdk version does not matter, should be true.
+ * @param uid affected by the change
+ * @param changeId the reported change id
+ * @param state of the reported change - enabled/disabled/only logged
+ * @param isKnownSystemApp do we know that the affected app is a system app? (if true is
+ * definitely a system app, if false it may or may not be a system app)
+ * @param isLoggableBySdk whether debug logging is allowed for this change based on target
+ * SDK version. This is combined with other logic to determine whether
+ * to actually log. If the sdk version does not matter, should be true.
*/
- public void reportChange(int uid, long changeId, int state, boolean isLoggableBySdk) {
+ public void reportChange(int uid, long changeId, int state, boolean isKnownSystemApp,
+ boolean isLoggableBySdk) {
boolean isAlreadyReported =
checkAndSetIsAlreadyReported(uid, new ChangeReport(changeId, state));
- if (!isAlreadyReported) {
+ if (shouldWriteToStatsLog(isKnownSystemApp, isAlreadyReported)) {
FrameworkStatsLog.write(FrameworkStatsLog.APP_COMPATIBILITY_CHANGE_REPORTED, uid,
changeId, state, mSource);
}
@@ -116,7 +119,7 @@
* @param state of the reported change - enabled/disabled/only logged
*/
public void reportChange(int uid, long changeId, int state) {
- reportChange(uid, changeId, state, true);
+ reportChange(uid, changeId, state, false, true);
}
/**
@@ -136,14 +139,15 @@
/**
* Returns whether the next report should be logged to FrameworkStatsLog.
*
- * @param uid affected by the change
- * @param changeId the reported change id
- * @param state of the reported change - enabled/disabled/only logged
+ * @param isKnownSystemApp do we know that the affected app is a system app? (if true is
+ * definitely a system app, if false it may or may not be a system app)
+ * @param isAlreadyReported is the change already reported
* @return true if the report should be logged
*/
@VisibleForTesting
- boolean shouldWriteToStatsLog(int uid, long changeId, int state) {
- return !isAlreadyReported(uid, new ChangeReport(changeId, state));
+ boolean shouldWriteToStatsLog(boolean isKnownSystemApp, boolean isAlreadyReported) {
+ // We don't log where we know the source is a system app or is already reported
+ return !isKnownSystemApp && !isAlreadyReported;
}
/**
@@ -224,6 +228,19 @@
return mReportedChanges.getOrDefault(uid, EMPTY_SET).contains(report);
}
+ /**
+ * Returns whether the next report should be logged.
+ *
+ * @param uid affected by the change
+ * @param changeId the reported change id
+ * @param state of the reported change - enabled/disabled/only logged
+ * @return true if the report should be logged
+ */
+ @VisibleForTesting
+ boolean isAlreadyReported(int uid, long changeId, int state) {
+ return isAlreadyReported(uid, new ChangeReport(changeId, state));
+ }
+
private void markAsReported(int uid, ChangeReport report) {
mReportedChanges.computeIfAbsent(uid, NEW_CHANGE_REPORT_SET).add(report);
}
diff --git a/core/java/com/android/internal/jank/Cuj.java b/core/java/com/android/internal/jank/Cuj.java
index 23bd64d..618f622 100644
--- a/core/java/com/android/internal/jank/Cuj.java
+++ b/core/java/com/android/internal/jank/Cuj.java
@@ -147,8 +147,21 @@
*/
public static final int CUJ_DESKTOP_MODE_MAXIMIZE_WINDOW = 104;
+ /**
+ * Track fade-in animation when in SystemUI process fold
+ *
+ * <p>Tracking starts after the screen turns on and finish when the animation is over {@link
+ * com.android.systemui.unfold.FoldLightRevealOverlayAnimation#playFoldLightRevealOverlayAnimation} for the span
+ */
+ public static final int CUJ_FOLD_ANIM = 105;
+
+ /**
+ * Track window re-sizing interaction in desktop mode.
+ */
+ public static final int CUJ_DESKTOP_MODE_RESIZE_WINDOW = 106;
+
// When adding a CUJ, update this and make sure to also update CUJ_TO_STATSD_INTERACTION_TYPE.
- @VisibleForTesting static final int LAST_CUJ = CUJ_DESKTOP_MODE_MAXIMIZE_WINDOW;
+ @VisibleForTesting static final int LAST_CUJ = CUJ_DESKTOP_MODE_RESIZE_WINDOW;
/** @hide */
@IntDef({
@@ -244,7 +257,9 @@
CUJ_LAUNCHER_WIDGET_BOTTOM_SHEET_CLOSE_BACK,
CUJ_LAUNCHER_PRIVATE_SPACE_LOCK,
CUJ_LAUNCHER_PRIVATE_SPACE_UNLOCK,
- CUJ_DESKTOP_MODE_MAXIMIZE_WINDOW
+ CUJ_DESKTOP_MODE_MAXIMIZE_WINDOW,
+ CUJ_FOLD_ANIM,
+ CUJ_DESKTOP_MODE_RESIZE_WINDOW
})
@Retention(RetentionPolicy.SOURCE)
public @interface CujType {}
@@ -351,6 +366,8 @@
CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_LAUNCHER_PRIVATE_SPACE_LOCK] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_PRIVATE_SPACE_LOCK;
CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_LAUNCHER_PRIVATE_SPACE_UNLOCK] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_PRIVATE_SPACE_UNLOCK;
CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_DESKTOP_MODE_MAXIMIZE_WINDOW] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__DESKTOP_MODE_MAXIMIZE_WINDOW;
+ CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_FOLD_ANIM] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__FOLD_ANIM;
+ CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_DESKTOP_MODE_RESIZE_WINDOW] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__DESKTOP_MODE_RESIZE_WINDOW;
}
private Cuj() {
@@ -555,6 +572,10 @@
return "LAUNCHER_PRIVATE_SPACE_UNLOCK";
case CUJ_DESKTOP_MODE_MAXIMIZE_WINDOW:
return "DESKTOP_MODE_MAXIMIZE_WINDOW";
+ case CUJ_FOLD_ANIM:
+ return "FOLD_ANIM";
+ case CUJ_DESKTOP_MODE_RESIZE_WINDOW:
+ return "DESKTOP_MODE_RESIZE_WINDOW";
}
return "UNKNOWN";
}
diff --git a/core/java/com/android/internal/jank/OWNERS b/core/java/com/android/internal/jank/OWNERS
index 2f3bbee..5463883 100644
--- a/core/java/com/android/internal/jank/OWNERS
+++ b/core/java/com/android/internal/jank/OWNERS
@@ -4,4 +4,5 @@
ahanwu@google.com
vadimt@google.com
marcinoc@google.com
-pmuetschard@google.com
\ No newline at end of file
+pmuetschard@google.com
+nicomazz@google.com
diff --git a/core/java/com/android/internal/util/LatencyTracker.java b/core/java/com/android/internal/util/LatencyTracker.java
index 13efaf0..754f77e7 100644
--- a/core/java/com/android/internal/util/LatencyTracker.java
+++ b/core/java/com/android/internal/util/LatencyTracker.java
@@ -28,6 +28,7 @@
import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_FOLD_TO_AOD;
import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_NOTIFICATIONS_HIDDEN_FOR_MEASURE;
import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_NOTIFICATIONS_HIDDEN_FOR_MEASURE_WITH_SHADE_OPEN;
+import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_KEYGUARD_FACE_UNLOCK_TO_HOME;
import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_KEYGUARD_FPS_UNLOCK_TO_HOME;
import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_LOAD_SHARE_SHEET;
import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_LOCKSCREEN_UNLOCK;
@@ -227,7 +228,8 @@
public static final int ACTION_NOTIFICATION_BIG_PICTURE_LOADED = 23;
/**
- * Time it takes to unlock the device via udfps, until the whole launcher appears.
+ * Time it takes to unlock the device via fps,
+ * until either the launcher or the foreground app appears.
*/
public static final int ACTION_KEYGUARD_FPS_UNLOCK_TO_HOME = 24;
@@ -249,6 +251,12 @@
*/
public static final int ACTION_NOTIFICATIONS_HIDDEN_FOR_MEASURE_WITH_SHADE_OPEN = 27;
+ /**
+ * Time it takes to unlock the device via face,
+ * until either the launcher or the foreground app appears.
+ */
+ public static final int ACTION_KEYGUARD_FACE_UNLOCK_TO_HOME = 28;
+
private static final int[] ACTIONS_ALL = {
ACTION_EXPAND_PANEL,
ACTION_TOGGLE_RECENTS,
@@ -278,6 +286,7 @@
ACTION_BACK_SYSTEM_ANIMATION,
ACTION_NOTIFICATIONS_HIDDEN_FOR_MEASURE,
ACTION_NOTIFICATIONS_HIDDEN_FOR_MEASURE_WITH_SHADE_OPEN,
+ ACTION_KEYGUARD_FACE_UNLOCK_TO_HOME,
};
/** @hide */
@@ -310,6 +319,7 @@
ACTION_BACK_SYSTEM_ANIMATION,
ACTION_NOTIFICATIONS_HIDDEN_FOR_MEASURE,
ACTION_NOTIFICATIONS_HIDDEN_FOR_MEASURE_WITH_SHADE_OPEN,
+ ACTION_KEYGUARD_FACE_UNLOCK_TO_HOME,
})
@Retention(RetentionPolicy.SOURCE)
public @interface Action {
@@ -345,6 +355,7 @@
UIACTION_LATENCY_REPORTED__ACTION__ACTION_BACK_SYSTEM_ANIMATION,
UIACTION_LATENCY_REPORTED__ACTION__ACTION_NOTIFICATIONS_HIDDEN_FOR_MEASURE,
UIACTION_LATENCY_REPORTED__ACTION__ACTION_NOTIFICATIONS_HIDDEN_FOR_MEASURE_WITH_SHADE_OPEN,
+ UIACTION_LATENCY_REPORTED__ACTION__ACTION_KEYGUARD_FACE_UNLOCK_TO_HOME,
};
private final Object mLock = new Object();
@@ -539,6 +550,8 @@
return "ACTION_NOTIFICATIONS_HIDDEN_FOR_MEASURE";
case UIACTION_LATENCY_REPORTED__ACTION__ACTION_NOTIFICATIONS_HIDDEN_FOR_MEASURE_WITH_SHADE_OPEN:
return "ACTION_NOTIFICATIONS_HIDDEN_FOR_MEASURE_WITH_SHADE_OPEN";
+ case UIACTION_LATENCY_REPORTED__ACTION__ACTION_KEYGUARD_FACE_UNLOCK_TO_HOME:
+ return "ACTION_KEYGUARD_FACE_UNLOCK_TO_HOME";
default:
throw new IllegalArgumentException("Invalid action");
}
diff --git a/core/java/com/android/internal/widget/NotificationCloseButton.java b/core/java/com/android/internal/widget/NotificationCloseButton.java
new file mode 100644
index 0000000..bce266d
--- /dev/null
+++ b/core/java/com/android/internal/widget/NotificationCloseButton.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.widget;
+
+import android.annotation.ColorInt;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.content.res.Resources;
+import android.util.AttributeSet;
+import android.view.RemotableViewMethod;
+import android.view.View;
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.widget.Button;
+import android.widget.ImageView;
+import android.widget.RemoteViews;
+
+import com.android.internal.R;
+
+/**
+ * A close button in a notification
+ */
+@RemoteViews.RemoteView
+public class NotificationCloseButton extends ImageView {
+
+ @ColorInt private int mBackgroundColor;
+ @ColorInt private int mForegroundColor;
+
+ public NotificationCloseButton(Context context) {
+ this(context, null, 0, 0);
+ }
+
+ public NotificationCloseButton(Context context, @Nullable AttributeSet attrs) {
+ this(context, attrs, 0, 0);
+ }
+
+ public NotificationCloseButton(Context context, @Nullable AttributeSet attrs,
+ int defStyleAttr) {
+ this(context, attrs, defStyleAttr, 0);
+ }
+
+ public NotificationCloseButton(Context context, @Nullable AttributeSet attrs, int defStyleAttr,
+ int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ setContentDescription(mContext.getText(R.string.close_button_text));
+ boolean notificationCloseButtonSupported = Resources.getSystem().getBoolean(
+ com.android.internal.R.bool.config_notificationCloseButtonSupported);
+ this.setVisibility(notificationCloseButtonSupported ? View.VISIBLE : View.GONE);
+ }
+
+ @Override
+ public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
+ super.onInitializeAccessibilityNodeInfo(info);
+ info.setClassName(Button.class.getName());
+ }
+
+
+ private void updateColors() {
+ if (mBackgroundColor != 0) {
+ this.setBackgroundTintList(ColorStateList.valueOf(mBackgroundColor));
+ }
+ if (mForegroundColor != 0) {
+ this.setImageTintList(ColorStateList.valueOf(mForegroundColor));
+ }
+ }
+
+ /**
+ * Set the color used for the foreground.
+ */
+ @RemotableViewMethod
+ public void setForegroundColor(@ColorInt int color) {
+ mForegroundColor = color;
+ updateColors();
+ }
+
+ /**
+ * Sets the color used for the background.
+ */
+ @RemotableViewMethod
+ public void setBackgroundColor(@ColorInt int color) {
+ mBackgroundColor = color;
+ updateColors();
+ }
+}
diff --git a/core/jni/OWNERS b/core/jni/OWNERS
index 163f32e..b2bc19c 100644
--- a/core/jni/OWNERS
+++ b/core/jni/OWNERS
@@ -2,7 +2,7 @@
per-file *Camera*,*camera* = file:platform/frameworks/av:/camera/OWNERS
# Connectivity
-per-file android_net_* = codewiz@google.com, jchalard@google.com, lorenzo@google.com, reminv@google.com, satk@google.com
+per-file android_net_* = jchalard@google.com, lorenzo@google.com, reminv@google.com, satk@google.com
# Choreographer
per-file android_view_DisplayEventReceiver* = file:platform/frameworks/native:/services/surfaceflinger/OWNERS
@@ -84,7 +84,7 @@
# These are highly common-use files
per-file Android.bp = file:/graphics/java/android/graphics/OWNERS
per-file AndroidRuntime.cpp = file:/graphics/java/android/graphics/OWNERS
-per-file AndroidRuntime.cpp = calin@google.com, ngeoffray@google.com, oth@google.com
+per-file AndroidRuntime.cpp = file:platform/art:main:/OWNERS
# Although marked "view" this is mostly graphics stuff
per-file android_view_* = file:/graphics/java/android/graphics/OWNERS
# File used for Android Studio layoutlib
diff --git a/core/proto/android/server/activitymanagerservice.proto b/core/proto/android/server/activitymanagerservice.proto
index 921c41c..90069f1 100644
--- a/core/proto/android/server/activitymanagerservice.proto
+++ b/core/proto/android/server/activitymanagerservice.proto
@@ -1038,7 +1038,7 @@
optional int32 uid = 1;
repeated .android.app.ApplicationExitInfoProto app_exit_info = 2;
- repeated .android.app.ApplicationExitInfoProto app_recoverable_crash = 3;
+ repeated .android.app.ApplicationExitInfoProto app_recoverable_crash = 3 [deprecated=true];
}
repeated User users = 2;
}
diff --git a/core/proto/android/server/vibrator/vibratormanagerservice.proto b/core/proto/android/server/vibrator/vibratormanagerservice.proto
index 1d9b0db..5a4d6db 100644
--- a/core/proto/android/server/vibrator/vibratormanagerservice.proto
+++ b/core/proto/android/server/vibrator/vibratormanagerservice.proto
@@ -146,6 +146,7 @@
IGNORED_FROM_VIRTUAL_DEVICE = 26;
IGNORED_ON_WIRELESS_CHARGER = 27;
IGNORED_MISSING_PERMISSION = 28;
+ CANCELLED_BY_APP_OPS = 29;
reserved 17; // prev IGNORED_UNKNOWN_VIBRATION
}
}
diff --git a/core/proto/android/widget/remoteviews.proto b/core/proto/android/widget/remoteviews.proto
new file mode 100644
index 0000000..d24da03
--- /dev/null
+++ b/core/proto/android/widget/remoteviews.proto
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless optional 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.
+ */
+
+syntax = "proto2";
+
+option java_multiple_files = true;
+
+package android.widget;
+
+import "frameworks/base/core/proto/android/privacy.proto";
+
+/**
+ * An android.widget.RemoteViews object. This is used by RemoteViews.createPreviewFromProto
+ * and RemoteViews.writePreviewToProto.
+ *
+ * Any addition of fields here will require an update to the parsing code in RemoteViews.java.
+ * Otherwise the field will be ignored when parsing (with a logged warning).
+ *
+ * Do not change the tag number or type of any fields in order to maintain compatibility with
+ * previous versions. If a field is deleted, use `reserved` to mark its tag number.
+ */
+message RemoteViewsProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+ optional int32 mode = 1;
+ optional string package_name = 2;
+ optional string layout_id = 3;
+ optional string light_background_layout_id = 4;
+ optional string view_id = 5;
+ optional SizeFProto ideal_size = 6;
+ optional int32 apply_flags = 7;
+ optional int64 provider_instance_id = 8;
+ // RemoteViews for different sizes (created with RemoteViews(Map<SizeF, RemoteViews)
+ // constructor).
+ repeated RemoteViewsProto sized_remoteviews = 9;
+ // RemoteViews for portrait/landscape (created with RemoteViews(RemoteViews, RemoteViews)i
+ // constructor).
+ optional RemoteViewsProto portrait_remoteviews = 10;
+ optional RemoteViewsProto landscape_remoteviews = 11;
+ optional bool is_root = 12;
+ optional bool has_draw_instructions = 13;
+}
+
+
+message SizeFProto {
+ optional float width = 1;
+ optional float height = 2;
+}
diff --git a/core/res/res/drawable/notification_close_button_icon.xml b/core/res/res/drawable/notification_close_button_icon.xml
new file mode 100644
index 0000000..947cd5a
--- /dev/null
+++ b/core/res/res/drawable/notification_close_button_icon.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2024 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="@dimen/notification_close_button_size"
+ android:height="@dimen/notification_close_button_size"
+ android:viewportWidth="16.0"
+ android:viewportHeight="16.0">
+<path
+ android:fillColor="#FF000000"
+ android:pathData="M 12.6667 4.2733 L 11.7267 3.3333 L 8 7.06 L 4.2734 3.3333 L 3.3334
+4.2733 L 7.06 8 L 3.3334 11.7267 L 4.2734 12.6667 L 8 8.94 L 11.7267 12.6667 L 12.6667
+11.7267 L 8.94 8 L 12.6667 4.2733 Z"/>
+</vector>
\ No newline at end of file
diff --git a/core/res/res/layout/accessibility_button_chooser.xml b/core/res/res/layout/accessibility_button_chooser.xml
index 2f97bae..f50af15 100644
--- a/core/res/res/layout/accessibility_button_chooser.xml
+++ b/core/res/res/layout/accessibility_button_chooser.xml
@@ -47,6 +47,16 @@
android:paddingTop="8dp"
android:paddingBottom="8dp"/>
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:id="@+id/accessibility_button_prompt"
+ android:textAppearance="?attr/textAppearanceMedium"
+ android:text="@string/accessibility_button_instructional_text"
+ android:gravity="start|center_vertical"
+ android:paddingTop="8dp"
+ android:paddingBottom="8dp"/>
+
<GridView
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -57,16 +67,5 @@
android:horizontalSpacing="10dp"
android:stretchMode="columnWidth"
android:gravity="center"/>
-
- <TextView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:id="@+id/accessibility_button_prompt"
- android:textAppearance="?attr/textAppearanceMedium"
- android:text="@string/accessibility_button_instructional_text"
- android:gravity="start|center_vertical"
- android:paddingTop="8dp"
- android:paddingBottom="8dp"
- android:visibility="gone"/>
</LinearLayout>
</com.android.internal.widget.ResolverDrawerLayout>
diff --git a/core/res/res/layout/notification_close_button.xml b/core/res/res/layout/notification_close_button.xml
new file mode 100644
index 0000000..5eff84e
--- /dev/null
+++ b/core/res/res/layout/notification_close_button.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2024 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+
+<com.android.internal.widget.NotificationCloseButton
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/close_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="top|end"
+ android:contentDescription="@string/close_button_text"
+ android:visibility="gone"
+ android:src="@drawable/notification_close_button_icon"
+ android:padding="2dp"
+ android:scaleType="fitCenter"
+ android:importantForAccessibility="no"
+ >
+</com.android.internal.widget.NotificationCloseButton>
diff --git a/core/res/res/layout/notification_template_header.xml b/core/res/res/layout/notification_template_header.xml
index d80b765..e44c727 100644
--- a/core/res/res/layout/notification_template_header.xml
+++ b/core/res/res/layout/notification_template_header.xml
@@ -83,11 +83,28 @@
android:focusable="false"
/>
- <include layout="@layout/notification_expand_button"
+ <LinearLayout
+ android:id="@+id/notification_buttons_column"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
- android:layout_centerVertical="true"
- />
+ android:orientation="vertical"
+ >
+
+ <include layout="@layout/notification_close_button"
+ android:layout_width="@dimen/notification_close_button_size"
+ android:layout_height="@dimen/notification_close_button_size"
+ android:layout_gravity="end"
+ android:layout_marginEnd="20dp"
+ />
+
+ <include layout="@layout/notification_expand_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentEnd="true"
+ android:layout_centerVertical="true"
+ />
+
+ </LinearLayout>
</NotificationHeaderView>
diff --git a/core/res/res/layout/notification_template_material_base.xml b/core/res/res/layout/notification_template_material_base.xml
index 452df50..29f14a4 100644
--- a/core/res/res/layout/notification_template_material_base.xml
+++ b/core/res/res/layout/notification_template_material_base.xml
@@ -157,20 +157,38 @@
android:maxDrawableHeight="@dimen/notification_right_icon_size"
/>
- <FrameLayout
- android:id="@+id/expand_button_touch_container"
+ <LinearLayout
+ android:id="@+id/notification_buttons_column"
android:layout_width="wrap_content"
android:layout_height="match_parent"
- android:minWidth="@dimen/notification_content_margin_end"
+ android:layout_alignParentEnd="true"
+ android:orientation="vertical"
>
- <include layout="@layout/notification_expand_button"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical|end"
+ <include layout="@layout/notification_close_button"
+ android:layout_width="@dimen/notification_close_button_size"
+ android:layout_height="@dimen/notification_close_button_size"
+ android:layout_gravity="end"
+ android:layout_marginEnd="20dp"
/>
- </FrameLayout>
+ <FrameLayout
+ android:id="@+id/expand_button_touch_container"
+ android:layout_width="wrap_content"
+ android:layout_height="0dp"
+ android:layout_weight="1"
+ android:minWidth="@dimen/notification_content_margin_end"
+ >
+
+ <include layout="@layout/notification_expand_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical|end"
+ />
+
+ </FrameLayout>
+
+ </LinearLayout>
</LinearLayout>
diff --git a/core/res/res/layout/notification_template_material_conversation.xml b/core/res/res/layout/notification_template_material_conversation.xml
index ce8a904..13f2c37 100644
--- a/core/res/res/layout/notification_template_material_conversation.xml
+++ b/core/res/res/layout/notification_template_material_conversation.xml
@@ -107,13 +107,20 @@
>
<!--expand_button_container is dynamically placed between here and at the end of the
layout. It starts here since only FrameLayout layout params have gravity-->
- <FrameLayout
+ <LinearLayout
android:id="@+id/expand_button_container"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="end|top"
android:clipChildren="false"
- android:clipToPadding="false">
+ android:clipToPadding="false"
+ android:orientation="vertical">
+ <include layout="@layout/notification_close_button"
+ android:layout_width="@dimen/notification_close_button_size"
+ android:layout_height="@dimen/notification_close_button_size"
+ android:layout_gravity="end"
+ android:layout_marginEnd="20dp"
+ />
<!--expand_button_touch_container makes sure that we can nicely center the expand
content in the collapsed layout while the parent makes sure that we're never laid out
bigger than the messaging content.-->
@@ -145,6 +152,6 @@
android:layout_gravity="center"
/>
</LinearLayout>
- </FrameLayout>
+ </LinearLayout>
</FrameLayout>
</com.android.internal.widget.ConversationLayout>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 17666cf..105b099 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -567,14 +567,6 @@
It has been updated to affect other plug types. -->
<bool name="config_keepDreamingWhenUnplugging">false</bool>
- <!-- The timeout (in ms) to wait before attempting to reconnect to the dream overlay service if
- it becomes disconnected -->
- <integer name="config_dreamOverlayReconnectTimeoutMs">1000</integer> <!-- 1 second -->
- <!-- The maximum number of times to attempt reconnecting to the dream overlay service -->
- <integer name="config_dreamOverlayMaxReconnectAttempts">3</integer>
- <!-- The duration after which the dream overlay connection should be considered stable -->
- <integer name="config_minDreamOverlayDurationMs">10000</integer> <!-- 10 seconds -->
-
<!-- Auto-rotation behavior -->
<!-- If true, enables auto-rotation features using the accelerometer.
@@ -3917,6 +3909,7 @@
<item>countdown</item>
<item>schedule</item>
<item>event</item>
+ <item>custom_manual</item>
</string-array>
<!-- Priority repeat caller threshold, in minutes -->
@@ -6972,6 +6965,9 @@
Note that, indefinitely repeating vibrations are not allowed as shutdown vibrations. -->
<string name="config_defaultShutdownVibrationFile" />
+ <!-- Whether or not vibration is disabled during shutdown -->
+ <bool name="config_disableShutdownVibrationInZen">false</bool>
+
<!-- Whether single finger panning is enabled by default when magnification is on -->
<bool name="config_enable_a11y_magnification_single_panning">false</bool>
@@ -7088,6 +7084,9 @@
<!-- Whether the system uses auto-suspend mode. -->
<bool name="config_useAutoSuspend">true</bool>
+ <!-- Whether close/dismiss buttons are supported on notifications. -->
+ <bool name="config_notificationCloseButtonSupported">false</bool>
+
<!-- Whether to show GAIA education screen during account login of private space setup.
OEM/Partner can explicitly opt to disable the screen. -->
<bool name="config_enableGaiaEducationInPrivateSpace">true</bool>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 5fea515..6cba84b 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -355,6 +355,9 @@
<!-- the padding of the expand icon in the notification header -->
<dimen name="notification_expand_button_icon_padding">2dp</dimen>
+ <!-- the size of the notification close button -->
+ <dimen name="notification_close_button_size">16dp</dimen>
+
<!-- Vertical margin for the headerless notification content, when content has 1 line -->
<!-- 16 * 2 (margins) + 24 (1 line) = 56 (notification) -->
<dimen name="notification_headerless_margin_oneline">16dp</dimen>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index b6e8383..05c46b9 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -4844,19 +4844,19 @@
<!-- Text spoken when accessibility shortcut warning dialog is shown. [CHAR LIMIT=none] -->
<string name="accessibility_shortcut_spoken_feedback">Release the volume keys. To turn on <xliff:g id="service_name" example="TalkBack">%1$s</xliff:g>, press and hold both volume keys again for 3 seconds.</string>
- <!-- Text appearing in a prompt at the top of UI allowing the user to select a target service or feature to be assigned to the Accessibility button in the navigation bar. [CHAR LIMIT=none]-->
- <string name="accessibility_button_prompt_text">Choose a feature to use when you tap the accessibility button:</string>
+ <!-- Text appearing in a prompt at the top of UI allowing the user to select a target service or feature to be assigned to the Accessibility button in the navigation bar or in gesture navigation. [CHAR LIMIT=none]-->
+ <string name="accessibility_button_prompt_text">Choose a feature</string>
<!-- Text appearing in a prompt at the top of UI allowing the user to select a target service or feature to be assigned to the Accessibility button when gesture navigation is enabled [CHAR LIMIT=none] -->
- <string name="accessibility_gesture_prompt_text">Choose a feature to use with the accessibility gesture (swipe up from the bottom of the screen with two fingers):</string>
+ <string name="accessibility_gesture_prompt_text">Choose a feature</string>
<!-- Text appearing in a prompt at the top of UI allowing the user to select a target service or feature to be assigned to the Accessibility button when gesture navigation and TalkBack is enabled [CHAR LIMIT=none] -->
- <string name="accessibility_gesture_3finger_prompt_text">Choose a feature to use with the accessibility gesture (swipe up from the bottom of the screen with three fingers):</string>
+ <string name="accessibility_gesture_3finger_prompt_text">Choose a feature</string>
<!-- Text describing how to display UI allowing a user to select a target service or feature to be assigned to the Accessibility button in the navigation bar. [CHAR LIMIT=none]-->
- <string name="accessibility_button_instructional_text">To switch between features, touch & hold the accessibility button.</string>
+ <string name="accessibility_button_instructional_text">The feature will open next time you tap the accessibility button.</string>
<!-- Text describing how to display UI allowing a user to select a target service or feature to be assigned to the Accessibility button when gesture navigation is enabled. [CHAR LIMIT=none] -->
- <string name="accessibility_gesture_instructional_text">To switch between features, swipe up with two fingers and hold.</string>
+ <string name="accessibility_gesture_instructional_text">The feature will open next time you use this shortcut. Swipe up with two fingers from the bottom of your screen and release quickly.</string>
<!-- Text describing how to display UI allowing a user to select a target service or feature to be assigned to the Accessibility button when gesture navigation and TalkBack is enabled. [CHAR LIMIT=none] -->
- <string name="accessibility_gesture_3finger_instructional_text">To switch between features, swipe up with three fingers and hold.</string>
+ <string name="accessibility_gesture_3finger_instructional_text">The feature will open next time you use this shortcut. Swipe up with three fingers from the bottom of your screen and release quickly.</string>
<!-- Text used to describe system navigation features, shown within a UI allowing a user to assign system magnification features to the Accessibility button in the navigation bar. -->
<string name="accessibility_magnification_chooser_text">Magnification</string>
@@ -5430,6 +5430,10 @@
<string name="call_notification_screening_text">Screening an incoming call</string>
<string name="default_notification_channel_label">Uncategorized</string>
+ <string name="promotional_notification_channel_label">Promotions</string>
+ <string name="social_notification_channel_label">Social</string>
+ <string name="news_notification_channel_label">News</string>
+ <string name="recs_notification_channel_label">Recommendations</string>
<string name="importance_from_user">You set the importance of these notifications.</string>
<string name="importance_from_person">This is important because of the people involved.</string>
@@ -5981,6 +5985,10 @@
<string name="accessibility_system_action_hardware_a11y_shortcut_label">Accessibility Shortcut</string>
<!-- Label for dismissing the notification shade [CHAR LIMIT=NONE] -->
<string name="accessibility_system_action_dismiss_notification_shade">Dismiss Notification Shade</string>
+ <!-- Label for menu action [CHAR LIMIT=NONE] -->
+ <string name="accessibility_system_action_menu_label">Menu</string>
+ <!-- Label for media play/pause action [CHAR LIMIT=NONE] -->
+ <string name="accessibility_system_action_media_play_pause_label">Media Play/Pause</string>
<!-- Label for Dpad up action [CHAR LIMIT=NONE] -->
<string name="accessibility_system_action_dpad_up_label">Dpad Up</string>
<!-- Label for Dpad down action [CHAR LIMIT=NONE] -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 85397fa..0f54d89 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -521,6 +521,7 @@
<java-symbol type="bool" name="config_preferKeepClearForFocus" />
<java-symbol type="bool" name="config_hibernationDeletesOatArtifactsEnabled"/>
<java-symbol type="integer" name="config_defaultAnalogClockSecondsHandFps"/>
+ <java-symbol type="bool" name="config_notificationCloseButtonSupported"/>
<java-symbol type="bool" name="config_enableGaiaEducationInPrivateSpace"/>
<java-symbol type="color" name="tab_indicator_text_v4" />
@@ -2298,9 +2299,6 @@
<java-symbol type="array" name="config_disabledDreamComponents" />
<java-symbol type="bool" name="config_dismissDreamOnActivityStart" />
<java-symbol type="bool" name="config_resetScreenTimeoutOnUnexpectedDreamExit" />
- <java-symbol type="integer" name="config_dreamOverlayReconnectTimeoutMs" />
- <java-symbol type="integer" name="config_dreamOverlayMaxReconnectAttempts" />
- <java-symbol type="integer" name="config_minDreamOverlayDurationMs" />
<java-symbol type="array" name="config_loggable_dream_prefixes" />
<java-symbol type="string" name="config_dozeComponent" />
<java-symbol type="string" name="enable_explore_by_touch_warning_title" />
@@ -3171,6 +3169,7 @@
<java-symbol type="id" name="header_text_secondary_divider" />
<java-symbol type="drawable" name="ic_expand_notification" />
<java-symbol type="drawable" name="ic_collapse_notification" />
+ <java-symbol type="drawable" name="notification_close_button_icon" />
<java-symbol type="drawable" name="ic_expand_bundle" />
<java-symbol type="drawable" name="ic_collapse_bundle" />
<java-symbol type="drawable" name="ic_notification_summary_auto" />
@@ -3877,6 +3876,7 @@
<java-symbol type="string" name="expand_button_content_description_collapsed" />
<java-symbol type="string" name="expand_button_content_description_expanded" />
+ <java-symbol type="string" name="close_button_text" />
<java-symbol type="string" name="content_description_collapsed" />
<java-symbol type="string" name="content_description_expanded" />
@@ -4462,6 +4462,8 @@
<java-symbol type="string" name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" />
<java-symbol type="string" name="accessibility_system_action_hardware_a11y_shortcut_label" />
<java-symbol type="string" name="accessibility_system_action_dismiss_notification_shade" />
+ <java-symbol type="string" name="accessibility_system_action_menu_label" />
+ <java-symbol type="string" name="accessibility_system_action_media_play_pause_label" />
<java-symbol type="string" name="accessibility_system_action_dpad_up_label" />
<java-symbol type="string" name="accessibility_system_action_dpad_down_label" />
<java-symbol type="string" name="accessibility_system_action_dpad_left_label" />
@@ -5042,6 +5044,9 @@
<java-symbol type="string" name="ui_translation_accessibility_translation_finished" />
<java-symbol type="layout" name="notification_expand_button"/>
+ <java-symbol type="id" name="close_button" />
+ <java-symbol type="layout" name="notification_close_button"/>
+ <java-symbol type="id" name="notification_buttons_column" />
<java-symbol type="bool" name="config_supportsMicToggle" />
<java-symbol type="bool" name="config_supportsCamToggle" />
@@ -5425,6 +5430,7 @@
<java-symbol type="drawable" name="focus_event_pressed_key_background" />
<java-symbol type="drawable" name="focus_event_rotary_input_background" />
<java-symbol type="string" name="config_defaultShutdownVibrationFile" />
+ <java-symbol type="bool" name="config_disableShutdownVibrationInZen" />
<java-symbol type="string" name="lockscreen_too_many_failed_attempts_countdown" />
<java-symbol type="bool" name="config_enable_a11y_magnification_single_panning" />
@@ -5516,6 +5522,12 @@
<java-symbol type="string" name="biometric_dangling_notification_action_set_up" />
<java-symbol type="string" name="biometric_dangling_notification_action_not_now" />
+ <!-- Notification bundles -->
+ <java-symbol type="string" name="promotional_notification_channel_label"/>
+ <java-symbol type="string" name="social_notification_channel_label"/>
+ <java-symbol type="string" name="news_notification_channel_label"/>
+ <java-symbol type="string" name="recs_notification_channel_label"/>
+
<!-- Priority Modes icons -->
<java-symbol type="drawable" name="ic_zen_mode_type_bedtime" />
<java-symbol type="drawable" name="ic_zen_mode_type_driving" />
@@ -5526,5 +5538,4 @@
<java-symbol type="drawable" name="ic_zen_mode_type_schedule_time" />
<java-symbol type="drawable" name="ic_zen_mode_type_theater" />
<java-symbol type="drawable" name="ic_zen_mode_type_unknown" />
-
</resources>
diff --git a/core/tests/BroadcastRadioTests/src/android/hardware/radio/RadioMetadataTest.java b/core/tests/BroadcastRadioTests/src/android/hardware/radio/RadioMetadataTest.java
index b3a0aba..db3a2da 100644
--- a/core/tests/BroadcastRadioTests/src/android/hardware/radio/RadioMetadataTest.java
+++ b/core/tests/BroadcastRadioTests/src/android/hardware/radio/RadioMetadataTest.java
@@ -470,6 +470,20 @@
}
@Test
+ public void equals_forMetadataWithDifferentContents_returnsFalse() {
+ mSetFlagsRule.enableFlags(Flags.FLAG_HD_RADIO_IMPROVED);
+ RadioMetadata metadata1 = mBuilder
+ .putStringArray(RadioMetadata.METADATA_KEY_UFIDS, UFIDS_VALUE)
+ .build();
+ RadioMetadata metadata2 = mBuilder
+ .putStringArray(RadioMetadata.METADATA_KEY_UFIDS, new String[]{"ufid3", "ufid2"})
+ .build();
+
+ mExpect.withMessage("Metadata with the same contents")
+ .that(metadata1).isNotEqualTo(metadata2);
+ }
+
+ @Test
public void describeContents_forMetadata() {
RadioMetadata metadata = mBuilder.build();
@@ -553,4 +567,25 @@
.that(metadata.getBitmap(RadioMetadata.METADATA_KEY_ICON))
.isEqualTo(bitmapResized);
}
+
+ @Test
+ public void toString_containsMetadataValues() {
+ mSetFlagsRule.enableFlags(Flags.FLAG_HD_RADIO_IMPROVED);
+ RadioMetadata metadataExpected = mBuilder
+ .putInt(RadioMetadata.METADATA_KEY_RDS_PI, INT_KEY_VALUE)
+ .putString(RadioMetadata.METADATA_KEY_ARTIST, ARTIST_KEY_VALUE)
+ .putStringArray(RadioMetadata.METADATA_KEY_UFIDS, UFIDS_VALUE)
+ .build();
+
+ String metadateString = metadataExpected.toString();
+
+ mExpect.withMessage("RDS PI value in converted sting for metadata")
+ .that(metadateString).contains(Integer.toString(INT_KEY_VALUE));
+ mExpect.withMessage("Artist value in converted sting for metadata")
+ .that(metadateString).contains(ARTIST_KEY_VALUE);
+ for (int i = 0; i < UFIDS_VALUE.length; i++) {
+ mExpect.withMessage("UFIDs[%s] value in converted sting for metadata", i)
+ .that(metadateString).contains(UFIDS_VALUE[i]);
+ }
+ }
}
diff --git a/core/tests/PlatformCompatFramework/src/com/android/internal/compat/ChangeReporterTest.java b/core/tests/PlatformCompatFramework/src/com/android/internal/compat/ChangeReporterTest.java
index 12a42f9..ed5e4af 100644
--- a/core/tests/PlatformCompatFramework/src/com/android/internal/compat/ChangeReporterTest.java
+++ b/core/tests/PlatformCompatFramework/src/com/android/internal/compat/ChangeReporterTest.java
@@ -37,15 +37,20 @@
long myChangeId = 500L, otherChangeId = 600L;
int myState = ChangeReporter.STATE_ENABLED, otherState = ChangeReporter.STATE_DISABLED;
- assertTrue(reporter.shouldWriteToStatsLog(myUid, myChangeId, myState));
+ assertTrue(reporter.shouldWriteToStatsLog(false,
+ reporter.isAlreadyReported(myUid, myChangeId, myState)));
reporter.reportChange(myUid, myChangeId, myState);
// Same report will not be logged again.
- assertFalse(reporter.shouldWriteToStatsLog(myUid, myChangeId, myState));
+ assertFalse(reporter.shouldWriteToStatsLog(false,
+ reporter.isAlreadyReported(myUid, myChangeId, myState)));
// Other reports will be logged.
- assertTrue(reporter.shouldWriteToStatsLog(otherUid, myChangeId, myState));
- assertTrue(reporter.shouldWriteToStatsLog(myUid, otherChangeId, myState));
- assertTrue(reporter.shouldWriteToStatsLog(myUid, myChangeId, otherState));
+ assertTrue(reporter.shouldWriteToStatsLog(false,
+ reporter.isAlreadyReported(otherUid, myChangeId, myState)));
+ assertTrue(reporter.shouldWriteToStatsLog(false,
+ reporter.isAlreadyReported(myUid, otherChangeId, myState)));
+ assertTrue(reporter.shouldWriteToStatsLog(false,
+ reporter.isAlreadyReported(myUid, myChangeId, otherState)));
}
@Test
@@ -55,15 +60,18 @@
long myChangeId = 500L;
int myState = ChangeReporter.STATE_ENABLED;
- assertTrue(reporter.shouldWriteToStatsLog(myUid, myChangeId, myState));
+ assertTrue(reporter.shouldWriteToStatsLog(false,
+ reporter.isAlreadyReported(myUid, myChangeId, myState)));
reporter.reportChange(myUid, myChangeId, myState);
// Same report will not be logged again.
- assertFalse(reporter.shouldWriteToStatsLog(myUid, myChangeId, myState));
+ assertFalse(reporter.shouldWriteToStatsLog(false,
+ reporter.isAlreadyReported(myUid, myChangeId, myState)));
reporter.resetReportedChanges(myUid);
// Same report will be logged again after reset.
- assertTrue(reporter.shouldWriteToStatsLog(myUid, myChangeId, myState));
+ assertTrue(reporter.shouldWriteToStatsLog(false,
+ reporter.isAlreadyReported(myUid, myChangeId, myState)));
}
@Test
@@ -196,4 +204,21 @@
// off.
assertTrue(reporter.shouldWriteToDebug(myUid, myChangeId, myDisabledState, false));
}
+
+ @Test
+ public void testDontLogSystemApps() {
+ // Verify we don't log an app if we know it's a system app when source is system server.
+ ChangeReporter systemServerReporter =
+ new ChangeReporter(ChangeReporter.SOURCE_SYSTEM_SERVER);
+
+ assertFalse(systemServerReporter.shouldWriteToStatsLog(true, false));
+ assertFalse(systemServerReporter.shouldWriteToStatsLog(true, true));
+
+ // Verify we don't log an app if we know it's a system app when source is unknown.
+ ChangeReporter unknownReporter =
+ new ChangeReporter(ChangeReporter.SOURCE_UNKNOWN_SOURCE);
+
+ assertFalse(unknownReporter.shouldWriteToStatsLog(true, false));
+ assertFalse(unknownReporter.shouldWriteToStatsLog(true, true));
+ }
}
diff --git a/core/tests/coretests/Android.bp b/core/tests/coretests/Android.bp
index 41696df..d277169 100644
--- a/core/tests/coretests/Android.bp
+++ b/core/tests/coretests/Android.bp
@@ -63,6 +63,7 @@
"-c fa",
],
static_libs: [
+ "A11yChecker",
"collector-device-lib-platform",
"frameworks-base-testutils",
"core-test-rules", // for libcore.dalvik.system.CloseGuardSupport
diff --git a/core/tests/coretests/src/android/app/servertransaction/ClientTransactionListenerControllerTest.java b/core/tests/coretests/src/android/app/servertransaction/ClientTransactionListenerControllerTest.java
index ee1d1e1..3104f16 100644
--- a/core/tests/coretests/src/android/app/servertransaction/ClientTransactionListenerControllerTest.java
+++ b/core/tests/coretests/src/android/app/servertransaction/ClientTransactionListenerControllerTest.java
@@ -21,7 +21,6 @@
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
import static com.android.window.flags.Flags.FLAG_BUNDLE_CLIENT_TRANSACTION_FLAG;
-import static com.android.window.flags.Flags.FLAG_WINDOW_TOKEN_CONFIG_THREAD_SAFE;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
@@ -192,8 +191,6 @@
@Test
public void testWindowTokenClient_onConfigurationChanged() {
- mSetFlagsRule.enableFlags(FLAG_WINDOW_TOKEN_CONFIG_THREAD_SAFE);
-
doNothing().when(mController).onContextConfigurationPreChanged(any());
doNothing().when(mController).onContextConfigurationPostChanged(any());
diff --git a/core/tests/coretests/src/android/hardware/biometrics/BiometricPromptTest.java b/core/tests/coretests/src/android/hardware/biometrics/BiometricPromptTest.java
index ca91542..5464ea3 100644
--- a/core/tests/coretests/src/android/hardware/biometrics/BiometricPromptTest.java
+++ b/core/tests/coretests/src/android/hardware/biometrics/BiometricPromptTest.java
@@ -28,6 +28,7 @@
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -209,6 +210,25 @@
"The number of list items exceeds ");
}
+ @Test
+ public void testOnDialogDismissed_dialogDismissedNegative() throws RemoteException {
+ final ArgumentCaptor<IBiometricServiceReceiver> biometricServiceReceiverCaptor =
+ ArgumentCaptor.forClass(IBiometricServiceReceiver.class);
+ final BiometricPrompt.AuthenticationCallback callback =
+ mock(BiometricPrompt.AuthenticationCallback.class);
+ mBiometricPrompt.authenticate(mCancellationSignal, mExecutor, callback);
+ mLooper.dispatchAll();
+
+ verify(mService).authenticate(any(), anyLong(), anyInt(),
+ biometricServiceReceiverCaptor.capture(), anyString(), any());
+
+ biometricServiceReceiverCaptor.getValue().onDialogDismissed(
+ BiometricPrompt.DISMISSED_REASON_NEGATIVE);
+
+ verify(callback).onAuthenticationError(BiometricConstants.BIOMETRIC_ERROR_USER_CANCELED,
+ null /* errString */);
+ }
+
private String generateRandomString(int charNum) {
final Random random = new Random();
final StringBuilder longString = new StringBuilder(charNum);
diff --git a/core/tests/coretests/src/android/net/OWNERS b/core/tests/coretests/src/android/net/OWNERS
index beb77dc..831f444 100644
--- a/core/tests/coretests/src/android/net/OWNERS
+++ b/core/tests/coretests/src/android/net/OWNERS
@@ -1,5 +1,5 @@
include /services/core/java/com/android/server/net/OWNERS
-per-file SSL*,Url* = prb@google.com,oth@google.com,narayan@google.com,ngeoffray@google.com
+per-file SSL*,Url* = file:platform/libcore:main:/OWNERS_net_tests
per-file SntpClient* = file:/services/core/java/com/android/server/timedetector/OWNERS
per-file Uri* = varunshah@google.com
diff --git a/core/tests/coretests/src/android/view/accessibility/a11ychecker/AccessibilityNodePathBuilderTest.java b/core/tests/coretests/src/android/view/accessibility/a11ychecker/AccessibilityNodePathBuilderTest.java
new file mode 100644
index 0000000..438277b
--- /dev/null
+++ b/core/tests/coretests/src/android/view/accessibility/a11ychecker/AccessibilityNodePathBuilderTest.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.accessibility.a11ychecker;
+
+import static android.view.accessibility.a11ychecker.MockAccessibilityNodeInfoBuilder.PACKAGE_NAME;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.widget.FrameLayout;
+import android.widget.TextView;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.internal.widget.RecyclerView;
+
+import com.google.common.collect.ImmutableList;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class AccessibilityNodePathBuilderTest {
+
+ public static final String RESOURCE_ID_PREFIX = PACKAGE_NAME + ":id/";
+
+ @Test
+ public void createNodePath_pathWithResourceNames() {
+ AccessibilityNodeInfo child = new MockAccessibilityNodeInfoBuilder()
+ .setViewIdResourceName(RESOURCE_ID_PREFIX + "child_node")
+ .build();
+ AccessibilityNodeInfo parent =
+ new MockAccessibilityNodeInfoBuilder()
+ .setViewIdResourceName(RESOURCE_ID_PREFIX + "parent_node")
+ .addChildren(ImmutableList.of(child))
+ .build();
+ AccessibilityNodeInfo root =
+ new MockAccessibilityNodeInfoBuilder()
+ .setViewIdResourceName(RESOURCE_ID_PREFIX + "root_node")
+ .addChildren(ImmutableList.of(parent))
+ .build();
+
+ assertThat(AccessibilityNodePathBuilder.createNodePath(child))
+ .isEqualTo(PACKAGE_NAME + ":root_node/parent_node[1]/child_node[1]");
+ assertThat(AccessibilityNodePathBuilder.createNodePath(parent))
+ .isEqualTo(PACKAGE_NAME + ":root_node/parent_node[1]");
+ assertThat(AccessibilityNodePathBuilder.createNodePath(root))
+ .isEqualTo(PACKAGE_NAME + ":root_node");
+ }
+
+ @Test
+ public void createNodePath_pathWithoutResourceNames() {
+ AccessibilityNodeInfo child =
+ new MockAccessibilityNodeInfoBuilder()
+ .setClassName(TextView.class.getName())
+ .build();
+ AccessibilityNodeInfo parent =
+
+ new MockAccessibilityNodeInfoBuilder()
+ .setClassName(RecyclerView.class.getName())
+ .addChildren(ImmutableList.of(child))
+ .build();
+ AccessibilityNodeInfo root =
+ new MockAccessibilityNodeInfoBuilder()
+ .setClassName(FrameLayout.class.getName())
+ .addChildren(ImmutableList.of(parent))
+ .build();
+
+ assertThat(AccessibilityNodePathBuilder.createNodePath(child))
+ .isEqualTo(PACKAGE_NAME + ":FrameLayout/RecyclerView[1]/TextView[1]");
+ assertThat(AccessibilityNodePathBuilder.createNodePath(parent))
+ .isEqualTo(PACKAGE_NAME + ":FrameLayout/RecyclerView[1]");
+ assertThat(AccessibilityNodePathBuilder.createNodePath(root))
+ .isEqualTo(PACKAGE_NAME + ":FrameLayout");
+ }
+
+ @Test
+ public void createNodePath_parentWithMultipleChildren() {
+ AccessibilityNodeInfo child1 =
+ new MockAccessibilityNodeInfoBuilder()
+ .setViewIdResourceName(RESOURCE_ID_PREFIX + "child1")
+ .build();
+ AccessibilityNodeInfo child2 =
+ new MockAccessibilityNodeInfoBuilder()
+ .setClassName(TextView.class.getName())
+ .build();
+ AccessibilityNodeInfo parent =
+ new MockAccessibilityNodeInfoBuilder()
+ .setClassName(FrameLayout.class.getName())
+ .addChildren(ImmutableList.of(child1, child2))
+ .build();
+
+ assertThat(AccessibilityNodePathBuilder.createNodePath(child1))
+ .isEqualTo(PACKAGE_NAME + ":FrameLayout/child1[1]");
+ assertThat(AccessibilityNodePathBuilder.createNodePath(child2))
+ .isEqualTo(PACKAGE_NAME + ":FrameLayout/TextView[2]");
+ assertThat(AccessibilityNodePathBuilder.createNodePath(parent))
+ .isEqualTo(PACKAGE_NAME + ":FrameLayout");
+ }
+
+ @Test
+ public void createNodePath_handlesDifferentIdFormats() {
+ AccessibilityNodeInfo child1 =
+ new MockAccessibilityNodeInfoBuilder()
+ .setViewIdResourceName(RESOURCE_ID_PREFIX + "childId")
+ .build();
+ AccessibilityNodeInfo child2 =
+ new MockAccessibilityNodeInfoBuilder()
+ .setViewIdResourceName(RESOURCE_ID_PREFIX + "child/Id/With/Slash")
+ .build();
+ AccessibilityNodeInfo child3 =
+ new MockAccessibilityNodeInfoBuilder()
+ .setViewIdResourceName("childIdWithoutPrefix")
+ .build();
+ AccessibilityNodeInfo parent =
+ new MockAccessibilityNodeInfoBuilder()
+ .addChildren(ImmutableList.of(child1, child2, child3))
+ .setViewIdResourceName(RESOURCE_ID_PREFIX + "parentId")
+ .build();
+
+ assertThat(AccessibilityNodePathBuilder.createNodePath(child1))
+ .isEqualTo(PACKAGE_NAME + ":parentId/childId[1]");
+ assertThat(AccessibilityNodePathBuilder.createNodePath(child2))
+ .isEqualTo(PACKAGE_NAME + ":parentId/child/Id/With/Slash[2]");
+ assertThat(AccessibilityNodePathBuilder.createNodePath(child3))
+ .isEqualTo(PACKAGE_NAME + ":parentId/childIdWithoutPrefix[3]");
+ assertThat(AccessibilityNodePathBuilder.createNodePath(parent))
+ .isEqualTo(PACKAGE_NAME + ":parentId");
+ }
+
+}
diff --git a/core/tests/coretests/src/android/view/accessibility/a11ychecker/MockAccessibilityNodeInfoBuilder.java b/core/tests/coretests/src/android/view/accessibility/a11ychecker/MockAccessibilityNodeInfoBuilder.java
new file mode 100644
index 0000000..e363f0c
--- /dev/null
+++ b/core/tests/coretests/src/android/view/accessibility/a11ychecker/MockAccessibilityNodeInfoBuilder.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.accessibility.a11ychecker;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.view.accessibility.AccessibilityNodeInfo;
+
+import java.util.List;
+
+final class MockAccessibilityNodeInfoBuilder {
+ static final String PACKAGE_NAME = "com.example.app";
+ private final AccessibilityNodeInfo mMockNodeInfo = mock(AccessibilityNodeInfo.class);
+
+ MockAccessibilityNodeInfoBuilder() {
+ when(mMockNodeInfo.getPackageName()).thenReturn(PACKAGE_NAME);
+ }
+
+ MockAccessibilityNodeInfoBuilder setClassName(String className) {
+ when(mMockNodeInfo.getClassName()).thenReturn(className);
+ return this;
+ }
+
+ MockAccessibilityNodeInfoBuilder setViewIdResourceName(String
+ viewIdResourceName) {
+ when(mMockNodeInfo.getViewIdResourceName()).thenReturn(viewIdResourceName);
+ return this;
+ }
+
+ MockAccessibilityNodeInfoBuilder addChildren(List<AccessibilityNodeInfo>
+ children) {
+ when(mMockNodeInfo.getChildCount()).thenReturn(children.size());
+ for (int i = 0; i < children.size(); i++) {
+ when(mMockNodeInfo.getChild(i)).thenReturn(children.get(i));
+ when(children.get(i).getParent()).thenReturn(mMockNodeInfo);
+ }
+ return this;
+ }
+
+ AccessibilityNodeInfo build() {
+ return mMockNodeInfo;
+ }
+}
diff --git a/core/tests/coretests/src/android/view/accessibility/a11ychecker/OWNERS b/core/tests/coretests/src/android/view/accessibility/a11ychecker/OWNERS
new file mode 100644
index 0000000..872a180
--- /dev/null
+++ b/core/tests/coretests/src/android/view/accessibility/a11ychecker/OWNERS
@@ -0,0 +1,5 @@
+# Android Accessibility Framework owners
+include /core/java/android/view/accessibility/a11ychecker/OWNERS
+include /services/accessibility/OWNERS
+
+yaraabdullatif@google.com
diff --git a/core/tests/coretests/src/android/widget/RemoteViewsProtoTest.java b/core/tests/coretests/src/android/widget/RemoteViewsProtoTest.java
new file mode 100644
index 0000000..8e9ba7b
--- /dev/null
+++ b/core/tests/coretests/src/android/widget/RemoteViewsProtoTest.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.widget;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import android.content.Context;
+import android.util.SizeF;
+import android.util.proto.ProtoInputStream;
+import android.util.proto.ProtoOutputStream;
+import android.view.View;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.frameworks.coretests.R;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.runner.RunWith;
+
+import java.util.Map;
+
+/**
+ * Tests for RemoteViews.
+ */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class RemoteViewsProtoTest {
+
+ // This can point to any other package which exists on the device.
+ private static final String OTHER_PACKAGE = "com.android.systemui";
+
+ @Rule
+ public final ExpectedException exception = ExpectedException.none();
+
+ private Context mContext;
+ private String mPackage;
+ private LinearLayout mContainer;
+
+ @Before
+ public void setup() {
+ mContext = InstrumentationRegistry.getContext();
+ mPackage = mContext.getPackageName();
+ mContainer = new LinearLayout(mContext);
+ }
+
+ @Test
+ public void copy_canStillBeApplied() {
+ RemoteViews original = new RemoteViews(mPackage, R.layout.remote_views_test);
+
+ RemoteViews clone = recreateFromProto(original);
+
+ clone.apply(mContext, mContainer);
+ }
+
+ @SuppressWarnings("ReturnValueIgnored")
+ @Test
+ public void clone_repeatedly() {
+ RemoteViews original = new RemoteViews(mPackage, R.layout.remote_views_test);
+
+ recreateFromProto(original);
+ recreateFromProto(original);
+
+ original.apply(mContext, mContainer);
+ }
+
+ @Test
+ public void clone_chained() {
+ RemoteViews original = new RemoteViews(mPackage, R.layout.remote_views_test);
+
+ RemoteViews clone = recreateFromProto(recreateFromProto(original));
+
+
+ clone.apply(mContext, mContainer);
+ }
+
+ @Test
+ public void landscapePortraitViews_lightBackgroundLayoutFlag() {
+ RemoteViews inner = new RemoteViews(mPackage, R.layout.remote_views_text);
+ inner.setLightBackgroundLayoutId(R.layout.remote_views_light_background_text);
+
+ RemoteViews parent = new RemoteViews(inner, inner);
+ parent.addFlags(RemoteViews.FLAG_USE_LIGHT_BACKGROUND_LAYOUT);
+
+ View view = recreateFromProto(parent).apply(mContext, mContainer);
+ assertNull(view.findViewById(R.id.text));
+ assertNotNull(view.findViewById(R.id.light_background_text));
+ }
+
+ @Test
+ public void sizedViews_lightBackgroundLayoutFlag() {
+ RemoteViews inner = new RemoteViews(mPackage, R.layout.remote_views_text);
+ inner.setLightBackgroundLayoutId(R.layout.remote_views_light_background_text);
+
+ RemoteViews parent = new RemoteViews(
+ Map.of(new SizeF(0, 0), inner, new SizeF(100, 100), inner));
+ parent.addFlags(RemoteViews.FLAG_USE_LIGHT_BACKGROUND_LAYOUT);
+
+ View view = recreateFromProto(parent).apply(mContext, mContainer);
+ assertNull(view.findViewById(R.id.text));
+ assertNotNull(view.findViewById(R.id.light_background_text));
+ }
+
+ @Test
+ public void nestedLandscapeViews() throws Exception {
+ RemoteViews views = new RemoteViews(mPackage, R.layout.remote_views_test);
+ for (int i = 0; i < 10; i++) {
+ views = new RemoteViews(views, new RemoteViews(mPackage, R.layout.remote_views_test));
+ }
+ // writeTo/createFromProto works
+ recreateFromProto(views);
+
+ views = new RemoteViews(mPackage, R.layout.remote_views_test);
+ for (int i = 0; i < 11; i++) {
+ views = new RemoteViews(views, new RemoteViews(mPackage, R.layout.remote_views_test));
+ }
+ // writeTo/createFromProto fails
+ exception.expect(IllegalArgumentException.class);
+ recreateFromProtoNoRethrow(views);
+ }
+
+ private RemoteViews recreateFromProto(RemoteViews views) {
+ try {
+ return recreateFromProtoNoRethrow(views);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private RemoteViews recreateFromProtoNoRethrow(RemoteViews views) throws Exception {
+ ProtoOutputStream out = new ProtoOutputStream();
+ views.writePreviewToProto(mContext, out);
+ ProtoInputStream in = new ProtoInputStream(out.getBytes());
+ return RemoteViews.createPreviewFromProto(mContext, in);
+ }
+}
diff --git a/data/etc/com.android.settings.xml b/data/etc/com.android.settings.xml
index 7a4b6bc..99911de 100644
--- a/data/etc/com.android.settings.xml
+++ b/data/etc/com.android.settings.xml
@@ -69,5 +69,6 @@
<permission name="android.permission.LIST_ENABLED_CREDENTIAL_PROVIDERS" />
<permission name="android.permission.SATELLITE_COMMUNICATION" />
<permission name="android.permission.READ_SYSTEM_GRAMMATICAL_GENDER" />
+ <permission name="android.permission.SET_BIOMETRIC_DIALOG_ADVANCED" />
</privapp-permissions>
</permissions>
diff --git a/data/etc/package-shareduid-allowlist.xml b/data/etc/package-shareduid-allowlist.xml
index 2401d4a..3b35f44 100644
--- a/data/etc/package-shareduid-allowlist.xml
+++ b/data/etc/package-shareduid-allowlist.xml
@@ -32,4 +32,5 @@
<config>
<allow-package-shareduid package="android.test.settings" shareduid="android.uid.system" />
+ <allow-package-shareduid package="com.android.performanceLaunch" shareduid="com.android.performanceapp.tests" />
</config>
diff --git a/keystore/java/android/security/AndroidKeyStoreMaintenance.java b/keystore/java/android/security/AndroidKeyStoreMaintenance.java
index 24aea37..ecf4eb4 100644
--- a/keystore/java/android/security/AndroidKeyStoreMaintenance.java
+++ b/keystore/java/android/security/AndroidKeyStoreMaintenance.java
@@ -17,7 +17,6 @@
package android.security;
import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.ServiceSpecificException;
@@ -112,29 +111,6 @@
}
/**
- * Informs Keystore 2.0 about changing user's password
- *
- * @param userId - Android user id of the user
- * @param password - a secret derived from the synthetic password provided by the
- * LockSettingsService
- * @return 0 if successful or a {@code ResponseCode}
- * @hide
- */
- public static int onUserPasswordChanged(int userId, @Nullable byte[] password) {
- StrictMode.noteDiskWrite();
- try {
- getService().onUserPasswordChanged(userId, password);
- return 0;
- } catch (ServiceSpecificException e) {
- Log.e(TAG, "onUserPasswordChanged failed", e);
- return e.errorCode;
- } catch (Exception e) {
- Log.e(TAG, "Can not connect to keystore", e);
- return SYSTEM_ERROR;
- }
- }
-
- /**
* Tells Keystore that a user's LSKF is being removed, ie the user's lock screen is changing to
* Swipe or None. Keystore uses this notification to delete the user's auth-bound keys.
*
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/DividerPresenter.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/DividerPresenter.java
index 290fefa..822a07c 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/DividerPresenter.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/DividerPresenter.java
@@ -169,6 +169,11 @@
@GuardedBy("mLock")
private int mDividerPosition;
+ /** Indicates if there are containers to be finished since the divider has appeared. */
+ @GuardedBy("mLock")
+ @VisibleForTesting
+ private boolean mHasContainersToFinish = false;
+
DividerPresenter(int taskId, @NonNull DragEventCallback dragEventCallback,
@NonNull Executor callbackExecutor) {
mTaskId = taskId;
@@ -180,7 +185,8 @@
void updateDivider(
@NonNull WindowContainerTransaction wct,
@NonNull TaskFragmentParentInfo parentInfo,
- @Nullable SplitContainer topSplitContainer) {
+ @Nullable SplitContainer topSplitContainer,
+ boolean isTaskFragmentVanished) {
if (!Flags.activityEmbeddingInteractiveDividerFlag()) {
return;
}
@@ -188,6 +194,18 @@
synchronized (mLock) {
// Clean up the decor surface if top SplitContainer is null.
if (topSplitContainer == null) {
+ // Check if there are containers to finish but the TaskFragment hasn't vanished yet.
+ // Don't remove the decor surface and divider if so as the removal should happen in
+ // a following step when the TaskFragment has vanished. This ensures that the decor
+ // surface is removed only after the resulting Activity is ready to be shown,
+ // otherwise there may be flicker.
+ if (mHasContainersToFinish) {
+ if (isTaskFragmentVanished) {
+ setHasContainersToFinish(false);
+ } else {
+ return;
+ }
+ }
removeDecorSurfaceAndDivider(wct);
return;
}
@@ -868,6 +886,12 @@
}
}
+ void setHasContainersToFinish(boolean hasContainersToFinish) {
+ synchronized (mLock) {
+ mHasContainersToFinish = hasContainersToFinish;
+ }
+ }
+
private static boolean isDraggingToFullscreenAllowed(
@NonNull DividerAttributes dividerAttributes) {
// TODO(b/293654166) Use DividerAttributes.isDraggingToFullscreenAllowed when extension is
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
index f78e2b5..7ddda1f 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
@@ -673,7 +673,7 @@
break;
case TYPE_TASK_FRAGMENT_VANISHED:
mPresenter.removeTaskFragmentInfo(info);
- onTaskFragmentVanished(wct, info);
+ onTaskFragmentVanished(wct, info, taskId);
break;
case TYPE_TASK_FRAGMENT_PARENT_INFO_CHANGED:
onTaskFragmentParentInfoChanged(wct, taskId,
@@ -834,7 +834,7 @@
@VisibleForTesting
@GuardedBy("mLock")
void onTaskFragmentVanished(@NonNull WindowContainerTransaction wct,
- @NonNull TaskFragmentInfo taskFragmentInfo) {
+ @NonNull TaskFragmentInfo taskFragmentInfo, int taskId) {
final TaskFragmentContainer container = getContainer(taskFragmentInfo.getFragmentToken());
if (container != null) {
// Cleanup if the TaskFragment vanished is not requested by the organizer.
@@ -843,6 +843,11 @@
updateContainersInTaskIfVisible(wct, container.getTaskId());
}
cleanupTaskFragment(taskFragmentInfo.getFragmentToken());
+ final TaskContainer taskContainer = getTaskContainer(taskId);
+ if (taskContainer != null) {
+ // Update the divider to clean up any decor surfaces.
+ updateDivider(wct, taskContainer, true /* isTaskFragmentVanished */);
+ }
}
/**
@@ -884,7 +889,7 @@
// The divider need to be updated even if shouldUpdateContainer is false, because the decor
// surface may change in TaskFragmentParentInfo, which requires divider update but not
// container update.
- updateDivider(wct, taskContainer);
+ updateDivider(wct, taskContainer, false /* isTaskFragmentVanished */);
// If the last direct activity of the host task is dismissed and there's an always-on-top
// overlay container in the task, the overlay container should also be dismissed.
@@ -899,14 +904,23 @@
@GuardedBy("mLock")
void updateContainersInTaskIfVisible(@NonNull WindowContainerTransaction wct, int taskId) {
final TaskContainer taskContainer = getTaskContainer(taskId);
- if (taskContainer != null && taskContainer.isVisible()) {
+ if (taskContainer == null) {
+ return;
+ }
+
+ if (taskContainer.isVisible()) {
updateContainersInTask(wct, taskContainer);
+ } else if (Flags.fixNoContainerUpdateWithoutResize()) {
+ // the TaskFragmentContainers need to be updated when the task becomes visible
+ taskContainer.mTaskFragmentContainersNeedsUpdate = true;
}
}
@GuardedBy("mLock")
private void updateContainersInTask(@NonNull WindowContainerTransaction wct,
@NonNull TaskContainer taskContainer) {
+ taskContainer.mTaskFragmentContainersNeedsUpdate = false;
+
// Update all TaskFragments in the Task. Make a copy of the list since some may be
// removed on updating.
final List<TaskFragmentContainer> containers = taskContainer.getTaskFragmentContainers();
@@ -3257,12 +3271,15 @@
}
@GuardedBy("mLock")
- void updateDivider(
- @NonNull WindowContainerTransaction wct, @NonNull TaskContainer taskContainer) {
+ void updateDivider(@NonNull WindowContainerTransaction wct,
+ @NonNull TaskContainer taskContainer, boolean isTaskFragmentVanished) {
final DividerPresenter dividerPresenter = mDividerPresenters.get(taskContainer.getTaskId());
final TaskFragmentParentInfo parentInfo = taskContainer.getTaskFragmentParentInfo();
- dividerPresenter.updateDivider(
- wct, parentInfo, taskContainer.getTopNonFinishingSplitContainer());
+ final SplitContainer topSplitContainer = taskContainer.getTopNonFinishingSplitContainer();
+ if (dividerPresenter != null) {
+ dividerPresenter.updateDivider(
+ wct, parentInfo, topSplitContainer, isTaskFragmentVanished);
+ }
}
@Override
@@ -3292,6 +3309,9 @@
final List<TaskFragmentContainer> containersToFinish = new ArrayList<>();
taskContainer.updateTopSplitContainerForDivider(
dividerPresenter, containersToFinish);
+ if (!containersToFinish.isEmpty()) {
+ dividerPresenter.setHasContainersToFinish(true);
+ }
for (final TaskFragmentContainer container : containersToFinish) {
mPresenter.cleanupContainer(wct, container, false /* shouldFinishDependent */);
}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
index d888fa9..d0e49d8 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
@@ -374,7 +374,7 @@
updateTaskFragmentWindowingModeIfRegistered(wct, secondaryContainer, windowingMode);
updateAnimationParams(wct, primaryContainer.getTaskFragmentToken(), splitAttributes);
updateAnimationParams(wct, secondaryContainer.getTaskFragmentToken(), splitAttributes);
- mController.updateDivider(wct, taskContainer);
+ mController.updateDivider(wct, taskContainer, false /* isTaskFragmentVanished */);
}
private void setAdjacentTaskFragments(@NonNull WindowContainerTransaction wct,
@@ -757,7 +757,8 @@
void expandTaskFragment(@NonNull WindowContainerTransaction wct,
@NonNull TaskFragmentContainer container) {
super.expandTaskFragment(wct, container);
- mController.updateDivider(wct, container.getTaskContainer());
+ mController.updateDivider(
+ wct, container.getTaskContainer(), false /* isTaskFragmentVanished */);
}
static boolean shouldShowSplit(@NonNull SplitContainer splitContainer) {
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java
index ee00c4c..20ad53e 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java
@@ -108,6 +108,12 @@
private boolean mPlaceholderRuleSuppressed;
/**
+ * {@code true} if the TaskFragments in this Task needs to be updated next time the Task
+ * becomes visible. See {@link #shouldUpdateContainer(TaskFragmentParentInfo)}
+ */
+ boolean mTaskFragmentContainersNeedsUpdate;
+
+ /**
* The {@link TaskContainer} constructor
*
* @param taskId The ID of the Task, which must match {@link Activity#getTaskId()} with
@@ -185,7 +191,8 @@
// If the task properties equals regardless of starting position, don't
// need to update the container.
- return mInfo.getConfiguration().diffPublicOnly(configuration) != 0
+ return mTaskFragmentContainersNeedsUpdate
+ || mInfo.getConfiguration().diffPublicOnly(configuration) != 0
|| mInfo.getDisplayId() != info.getDisplayId();
}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java
index 070fa5b..859bc2c 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java
@@ -17,6 +17,7 @@
package androidx.window.extensions.layout;
import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.Display.INVALID_DISPLAY;
import static androidx.window.common.CommonFoldingFeature.COMMON_STATE_FLAT;
import static androidx.window.common.CommonFoldingFeature.COMMON_STATE_HALF_OPENED;
@@ -41,6 +42,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.UiContext;
+import androidx.annotation.VisibleForTesting;
import androidx.window.common.CommonFoldingFeature;
import androidx.window.common.DeviceStateManagerFoldingFeatureProducer;
import androidx.window.common.EmptyLifecycleCallbacksAdapter;
@@ -138,6 +140,10 @@
throw new IllegalArgumentException("Context must be a UI Context, which should be"
+ " an Activity, WindowContext or InputMethodService");
}
+ if (context.getAssociatedDisplayId() == INVALID_DISPLAY) {
+ Log.w(TAG, "The registered Context is a UI Context but not associated with any"
+ + " display. This Context may not receive any WindowLayoutInfo update");
+ }
mFoldingFeatureProducer.getData((features) -> {
WindowLayoutInfo newWindowLayout = getWindowLayoutInfo(context, features);
consumer.accept(newWindowLayout);
@@ -257,7 +263,8 @@
}
}
- private void onDisplayFeaturesChanged(List<CommonFoldingFeature> storedFeatures) {
+ @VisibleForTesting
+ void onDisplayFeaturesChanged(List<CommonFoldingFeature> storedFeatures) {
synchronized (mLock) {
mLastReportedFoldingFeatures.clear();
mLastReportedFoldingFeatures.addAll(storedFeatures);
@@ -409,9 +416,10 @@
* @return true if the display features should be reported for the UI Context, false otherwise.
*/
private boolean shouldReportDisplayFeatures(@NonNull @UiContext Context context) {
- int displayId = context.getDisplay().getDisplayId();
+ int displayId = context.getAssociatedDisplayId();
if (displayId != DEFAULT_DISPLAY) {
- // Display features are not supported on secondary displays.
+ // Display features are not supported on secondary displays or the context is not
+ // associated with any display.
return false;
}
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/DividerPresenterTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/DividerPresenterTest.java
index 4f51815..bc18cd2 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/DividerPresenterTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/DividerPresenterTest.java
@@ -82,6 +82,7 @@
*/
@Presubmit
@SmallTest
+@SuppressWarnings("GuardedBy")
@RunWith(AndroidJUnit4.class)
public class DividerPresenterTest {
@Rule
@@ -186,7 +187,8 @@
mDividerPresenter.updateDivider(
mTransaction,
mParentInfo,
- mSplitContainer);
+ mSplitContainer,
+ false /* isTaskFragmentVanished */);
assertNotEquals(mProperties, mDividerPresenter.mProperties);
verify(mRenderer).update();
@@ -206,7 +208,8 @@
mDividerPresenter.updateDivider(
mTransaction,
mParentInfo,
- mSplitContainer);
+ mSplitContainer,
+ false /* isTaskFragmentVanished */);
assertNotEquals(mProperties, mDividerPresenter.mProperties);
verify(mRenderer).update();
@@ -222,7 +225,8 @@
mDividerPresenter.updateDivider(
mTransaction,
mParentInfo,
- mSplitContainer);
+ mSplitContainer,
+ false /* isTaskFragmentVanished */);
assertEquals(mProperties, mDividerPresenter.mProperties);
verify(mRenderer, never()).update();
@@ -234,7 +238,42 @@
mDividerPresenter.updateDivider(
mTransaction,
mParentInfo,
- null /* splitContainer */);
+ null /* splitContainer */,
+ false /* isTaskFragmentVanished */);
+ final TaskFragmentOperation taskFragmentOperation = new TaskFragmentOperation.Builder(
+ OP_TYPE_REMOVE_TASK_FRAGMENT_DECOR_SURFACE)
+ .build();
+
+ verify(mTransaction).addTaskFragmentOperation(
+ mPrimaryContainerToken, taskFragmentOperation);
+ verify(mRenderer).release();
+ assertNull(mDividerPresenter.mRenderer);
+ assertNull(mDividerPresenter.mProperties);
+ assertNull(mDividerPresenter.mDecorSurfaceOwner);
+ }
+
+ @Test
+ public void testUpdateDivider_noChangeWhenHasContainersToFinishButTaskFragmentNotVanished() {
+ mDividerPresenter.setHasContainersToFinish(true);
+ mDividerPresenter.updateDivider(
+ mTransaction,
+ mParentInfo,
+ null /* splitContainer */,
+ false /* isTaskFragmentVanished */);
+
+ assertEquals(mProperties, mDividerPresenter.mProperties);
+ verify(mRenderer, never()).update();
+ verify(mTransaction, never()).addTaskFragmentOperation(any(), any());
+ }
+
+ @Test
+ public void testUpdateDivider_dividerRemovedWhenHasContainersToFinishAndTaskFragmentVanished() {
+ mDividerPresenter.setHasContainersToFinish(true);
+ mDividerPresenter.updateDivider(
+ mTransaction,
+ mParentInfo,
+ null /* splitContainer */,
+ true /* isTaskFragmentVanished */);
final TaskFragmentOperation taskFragmentOperation = new TaskFragmentOperation.Builder(
OP_TYPE_REMOVE_TASK_FRAGMENT_DECOR_SURFACE)
.build();
@@ -254,7 +293,8 @@
mDividerPresenter.updateDivider(
mTransaction,
mParentInfo,
- mSplitContainer);
+ mSplitContainer,
+ false /* isTaskFragmentVanished */);
final TaskFragmentOperation taskFragmentOperation = new TaskFragmentOperation.Builder(
OP_TYPE_REMOVE_TASK_FRAGMENT_DECOR_SURFACE)
.build();
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
index 640b1fc..efeec82 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
@@ -200,12 +200,14 @@
public void testOnTaskFragmentVanished() {
final TaskFragmentContainer tf = createTfContainer(mSplitController, mActivity);
doReturn(tf.getTaskFragmentToken()).when(mInfo).getFragmentToken();
+ doReturn(createTestTaskContainer()).when(mSplitController).getTaskContainer(TASK_ID);
// The TaskFragment has been removed in the server, we only need to cleanup the reference.
- mSplitController.onTaskFragmentVanished(mTransaction, mInfo);
+ mSplitController.onTaskFragmentVanished(mTransaction, mInfo, TASK_ID);
verify(mSplitPresenter, never()).deleteTaskFragment(any(), any());
verify(mSplitController).removeContainer(tf);
+ verify(mSplitController).updateDivider(any(), any(), anyBoolean());
verify(mTransaction, never()).finishActivity(any());
}
@@ -1152,7 +1154,7 @@
.setTaskFragmentInfo(info));
mSplitController.onTransactionReady(transaction);
- verify(mSplitController).onTaskFragmentVanished(any(), eq(info));
+ verify(mSplitController).onTaskFragmentVanished(any(), eq(info), anyInt());
verify(mSplitPresenter).onTransactionHandled(eq(transaction.getTransactionToken()), any(),
anyInt(), anyBoolean());
}
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/layout/WindowLayoutComponentImplTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/layout/WindowLayoutComponentImplTest.java
new file mode 100644
index 0000000..ff0a82f
--- /dev/null
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/layout/WindowLayoutComponentImplTest.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.window.extensions.layout;
+
+import static org.mockito.Mockito.mock;
+
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+import androidx.window.common.DeviceStateManagerFoldingFeatureProducer;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Collections;
+
+/**
+ * Test class for {@link WindowLayoutComponentImpl}.
+ *
+ * Build/Install/Run:
+ * atest WMJetpackUnitTests:WindowLayoutComponentImplTest
+ */
+@Presubmit
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class WindowLayoutComponentImplTest {
+
+ private WindowLayoutComponentImpl mWindowLayoutComponent;
+
+ @Before
+ public void setUp() {
+ mWindowLayoutComponent = new WindowLayoutComponentImpl(
+ ApplicationProvider.getApplicationContext(),
+ mock(DeviceStateManagerFoldingFeatureProducer.class));
+ }
+
+ @Test
+ public void testAddWindowLayoutListenerOnFakeUiContext_noCrash() {
+ final Context fakeUiContext = createTestContext();
+
+ mWindowLayoutComponent.addWindowLayoutInfoListener(fakeUiContext, info -> {});
+
+ mWindowLayoutComponent.onDisplayFeaturesChanged(Collections.emptyList());
+ }
+
+ private static Context createTestContext() {
+ return new FakeUiContext(ApplicationProvider.getApplicationContext());
+ }
+
+ /**
+ * A {@link android.content.Context} overrides {@link android.content.Context#isUiContext} to
+ * {@code true}.
+ */
+ private static class FakeUiContext extends ContextWrapper {
+
+ FakeUiContext(Context base) {
+ super(base);
+ }
+
+ @Override
+ public boolean isUiContext() {
+ return true;
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/aconfig/multitasking.aconfig b/libs/WindowManager/Shell/aconfig/multitasking.aconfig
index 112eb61..3b7eb29 100644
--- a/libs/WindowManager/Shell/aconfig/multitasking.aconfig
+++ b/libs/WindowManager/Shell/aconfig/multitasking.aconfig
@@ -121,3 +121,13 @@
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ name: "enable_taskbar_on_phones"
+ namespace: "multitasking"
+ description: "Enables taskbar on phones"
+ bug: "348007377"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/libs/WindowManager/Shell/res/layout/bubble_bar_expanded_view.xml b/libs/WindowManager/Shell/res/layout/bubble_bar_expanded_view.xml
index 34f03c2..501bedd 100644
--- a/libs/WindowManager/Shell/res/layout/bubble_bar_expanded_view.xml
+++ b/libs/WindowManager/Shell/res/layout/bubble_bar_expanded_view.xml
@@ -19,7 +19,7 @@
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:orientation="vertical"
- android:id="@+id/bubble_bar_expanded_view">
+ android:id="@+id/bubble_expanded_view">
<com.android.wm.shell.bubbles.bar.BubbleBarHandleView
android:id="@+id/bubble_bar_handle_view"
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipBoundsAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipBoundsAlgorithm.java
index 6ffeb97..58007b5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipBoundsAlgorithm.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipBoundsAlgorithm.java
@@ -27,7 +27,9 @@
import android.util.Size;
import android.view.Gravity;
+import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.R;
+import com.android.wm.shell.protolog.ShellProtoLogGroup;
import java.io.PrintWriter;
@@ -39,6 +41,9 @@
private static final String TAG = PipBoundsAlgorithm.class.getSimpleName();
private static final float INVALID_SNAP_FRACTION = -1f;
+ // The same value (with the same name) is used in Launcher.
+ private static final float PIP_ASPECT_RATIO_MISMATCH_THRESHOLD = 0.01f;
+
@NonNull private final PipBoundsState mPipBoundsState;
@NonNull protected final PipDisplayLayoutState mPipDisplayLayoutState;
@NonNull protected final SizeSpecSource mSizeSpecSource;
@@ -206,9 +211,27 @@
*/
public static boolean isSourceRectHintValidForEnterPip(Rect sourceRectHint,
Rect destinationBounds) {
- return sourceRectHint != null
- && sourceRectHint.width() > destinationBounds.width()
- && sourceRectHint.height() > destinationBounds.height();
+ if (sourceRectHint == null || sourceRectHint.isEmpty()) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "isSourceRectHintValidForEnterPip=false, empty hint");
+ return false;
+ }
+ if (sourceRectHint.width() <= destinationBounds.width()
+ || sourceRectHint.height() <= destinationBounds.height()) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "isSourceRectHintValidForEnterPip=false, hint(%s) is smaller"
+ + " than destination(%s)", sourceRectHint, destinationBounds);
+ return false;
+ }
+ final float reportedRatio = destinationBounds.width() / (float) destinationBounds.height();
+ final float inferredRatio = sourceRectHint.width() / (float) sourceRectHint.height();
+ if (Math.abs(reportedRatio - inferredRatio) > PIP_ASPECT_RATIO_MISMATCH_THRESHOLD) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "isSourceRectHintValidForEnterPip=false, hint(%s) does not match"
+ + " destination(%s) aspect ratio", sourceRectHint, destinationBounds);
+ return false;
+ }
+ return true;
}
public float getDefaultAspectRatio() {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipUtils.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipUtils.kt
index a09720d..3e9366f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipUtils.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipUtils.kt
@@ -34,6 +34,7 @@
import com.android.wm.shell.Flags
import com.android.wm.shell.protolog.ShellProtoLogGroup
import kotlin.math.abs
+import kotlin.math.roundToInt
/** A class that includes convenience methods. */
object PipUtils {
@@ -149,16 +150,16 @@
val appBoundsAspRatio = appBounds.width().toFloat() / appBounds.height()
val width: Int
val height: Int
- var left = 0
- var top = 0
+ var left = appBounds.left
+ var top = appBounds.top
if (appBoundsAspRatio < aspectRatio) {
width = appBounds.width()
- height = Math.round(width / aspectRatio)
- top = (appBounds.height() - height) / 2
+ height = (width / aspectRatio).roundToInt()
+ top = appBounds.top + (appBounds.height() - height) / 2
} else {
height = appBounds.height()
- width = Math.round(height * aspectRatio)
- left = (appBounds.width() - width) / 2
+ width = (height * aspectRatio).roundToInt()
+ left = appBounds.left + (appBounds.width() - width) / 2
}
return Rect(left, top, left + width, top + height)
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserver.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserver.kt
index 42ed988..e710560 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserver.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserver.kt
@@ -228,7 +228,6 @@
* Log the appropriate log event based on the new state of TasksInfos and previously cached
* state and update it
*/
- // TODO(b/326231724): Trigger logging when task size or position is changed.
private fun identifyLogEventAndUpdateState(
transitionInfo: TransitionInfo,
preTransitionVisibleFreeformTasks: SparseArray<TaskInfo>,
@@ -289,10 +288,17 @@
preTransitionVisibleFreeformTasks: SparseArray<TaskInfo>,
postTransitionVisibleFreeformTasks: SparseArray<TaskInfo>
) {
- // find new tasks that were added
postTransitionVisibleFreeformTasks.forEach { taskId, taskInfo ->
- if (!preTransitionVisibleFreeformTasks.containsKey(taskId)) {
- desktopModeEventLogger.logTaskAdded(sessionId, buildTaskUpdateForTask(taskInfo))
+ val currentTaskUpdate = buildTaskUpdateForTask(taskInfo)
+ val previousTaskInfo = preTransitionVisibleFreeformTasks[taskId]
+ when {
+ // new tasks added
+ previousTaskInfo == null ->
+ desktopModeEventLogger.logTaskAdded(sessionId, currentTaskUpdate)
+ // old tasks that were resized or repositioned
+ // TODO(b/347935387): Log changes only once they are stable.
+ buildTaskUpdateForTask(previousTaskInfo) != currentTaskUpdate ->
+ desktopModeEventLogger.logTaskInfoChanged(sessionId, currentTaskUpdate)
}
}
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 7d01580..9bf244e 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
@@ -46,6 +46,9 @@
val activeTasks: ArraySet<Int> = ArraySet(),
val visibleTasks: ArraySet<Int> = ArraySet(),
val minimizedTasks: ArraySet<Int> = ArraySet(),
+ // Tasks that are closing, but are still visible
+ // TODO(b/332682201): Remove when the repository state is updated via TransitionObserver
+ val closingTasks: ArraySet<Int> = ArraySet(),
// Tasks currently in freeform mode, ordered from top to bottom (top is at index 0).
val freeformTasksInZOrder: ArrayList<Int> = ArrayList(),
)
@@ -169,6 +172,42 @@
return result
}
+ /**
+ * Mark a task with given [taskId] as closing on given [displayId]
+ *
+ * @return `true` if the task was not closing on given [displayId]
+ */
+ fun addClosingTask(displayId: Int, taskId: Int): Boolean {
+ val added = displayData.getOrCreate(displayId).closingTasks.add(taskId)
+ if (added) {
+ KtProtoLog.d(
+ WM_SHELL_DESKTOP_MODE,
+ "DesktopTaskRepo: added closing task=%d displayId=%d",
+ taskId,
+ displayId
+ )
+ }
+ return added
+ }
+
+ /**
+ * Remove task with given [taskId] from closing tasks.
+ *
+ * @return `true` if the task was closing
+ */
+ fun removeClosingTask(taskId: Int): Boolean {
+ var removed = false
+ displayData.forEach { _, data ->
+ if (data.closingTasks.remove(taskId)) {
+ removed = true
+ }
+ }
+ if (removed) {
+ KtProtoLog.d(WM_SHELL_DESKTOP_MODE, "DesktopTaskRepo: remove closing task=%d", taskId)
+ }
+ return removed
+ }
+
/** Check if a task with the given [taskId] was marked as an active task */
fun isActiveTask(taskId: Int): Boolean {
return displayData.valueIterator().asSequence().any { data ->
@@ -176,6 +215,10 @@
}
}
+ /** Check if a task with the given [taskId] was marked as a closing task */
+ fun isClosingTask(taskId: Int): Boolean =
+ displayData.valueIterator().asSequence().any { data -> taskId in data.closingTasks }
+
/** Whether a task is visible. */
fun isVisibleTask(taskId: Int): Boolean {
return displayData.valueIterator().asSequence().any { data ->
@@ -190,10 +233,16 @@
}
}
- /** Check if a task with the given [taskId] is the only active task on its display */
- fun isOnlyActiveTask(taskId: Int): Boolean {
+ /**
+ * Check if a task with the given [taskId] is the only active, non-closing, not-minimized task
+ * on its display
+ */
+ fun isOnlyActiveNonClosingTask(taskId: Int): Boolean {
return displayData.valueIterator().asSequence().any { data ->
- data.activeTasks.singleOrNull() == taskId
+ data.activeTasks
+ .subtract(data.closingTasks)
+ .subtract(data.minimizedTasks)
+ .singleOrNull() == taskId
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
index c5111d6..d28cda3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
@@ -442,12 +442,21 @@
* active task.
*
* @param wct transaction to modify if the last active task is closed
+ * @param displayId display id of the window that's being closed
* @param taskId task id of the window that's being closed
*/
- fun onDesktopWindowClose(wct: WindowContainerTransaction, taskId: Int) {
- if (desktopModeTaskRepository.isOnlyActiveTask(taskId)) {
+ fun onDesktopWindowClose(wct: WindowContainerTransaction, displayId: Int, taskId: Int) {
+ if (desktopModeTaskRepository.isOnlyActiveNonClosingTask(taskId)) {
removeWallpaperActivity(wct)
}
+ if (!desktopModeTaskRepository.addClosingTask(displayId, taskId)) {
+ // Could happen if the task hasn't been removed from closing list after it disappeared
+ KtProtoLog.w(
+ WM_SHELL_DESKTOP_MODE,
+ "DesktopTasksController: the task with taskId=%d is already closing!",
+ taskId
+ )
+ }
}
/** Move a task with given `taskId` to fullscreen */
@@ -871,7 +880,7 @@
false
}
// Handle back navigation for the last window if wallpaper available
- shouldRemoveWallpaper(request) -> true
+ shouldHandleBackNavigation(request) -> true
// Only handle open or to front transitions
request.type != TRANSIT_OPEN && request.type != TRANSIT_TO_FRONT -> {
reason = "transition type not handled (${request.type})"
@@ -951,13 +960,9 @@
private fun shouldLaunchAsModal(task: TaskInfo) =
Flags.enableDesktopWindowingModalsPolicy() && isSingleTopActivityTranslucent(task)
- private fun shouldRemoveWallpaper(request: TransitionRequestInfo): Boolean {
+ private fun shouldHandleBackNavigation(request: TransitionRequestInfo): Boolean {
return Flags.enableDesktopWindowingWallpaperActivity() &&
- request.type == TRANSIT_TO_BACK &&
- request.triggerTask?.let { task ->
- desktopModeTaskRepository.isOnlyActiveTask(task.taskId)
- }
- ?: false
+ request.type == TRANSIT_TO_BACK
}
private fun handleFreeformTaskLaunch(
@@ -1026,15 +1031,24 @@
/** Handle back navigation by removing wallpaper activity if it's the last active task */
private fun handleBackNavigation(task: RunningTaskInfo): WindowContainerTransaction? {
- if (
- desktopModeTaskRepository.isOnlyActiveTask(task.taskId) &&
+ val wct = if (
+ desktopModeTaskRepository.isOnlyActiveNonClosingTask(task.taskId) &&
desktopModeTaskRepository.wallpaperActivityToken != null
) {
// Remove wallpaper activity when the last active task is removed
- return WindowContainerTransaction().also { wct -> removeWallpaperActivity(wct) }
+ WindowContainerTransaction().also { wct -> removeWallpaperActivity(wct) }
} else {
- return null
+ null
}
+ if (!desktopModeTaskRepository.addClosingTask(task.displayId, task.taskId)) {
+ // Could happen if the task hasn't been removed from closing list after it disappeared
+ KtProtoLog.w(
+ WM_SHELL_DESKTOP_MODE,
+ "DesktopTasksController: the task with taskId=%d is already closing!",
+ task.taskId
+ )
+ }
+ return wct
}
private fun addMoveToDesktopChanges(
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/OWNERS b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/OWNERS
index 1385f42..7ad68aa 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/OWNERS
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/OWNERS
@@ -5,3 +5,4 @@
nmusgrave@google.com
pbdr@google.com
tkachenkoi@google.com
+vaniadesmonda@google.com
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 7d2aa27..b88afb9 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
@@ -122,6 +122,10 @@
mDesktopModeTaskRepository.ifPresent(repository -> {
repository.removeFreeformTask(taskInfo.displayId, taskInfo.taskId);
repository.unminimizeTask(taskInfo.displayId, taskInfo.taskId);
+ if (repository.removeClosingTask(taskInfo.taskId)) {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE,
+ "Removing closing freeform task: #%d", taskInfo.taskId);
+ }
if (repository.removeActiveTask(taskInfo.taskId)) {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE,
"Removing active freeform task: #%d", taskInfo.taskId);
@@ -150,6 +154,10 @@
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE,
"Adding active freeform task: #%d", taskInfo.taskId);
}
+ } else if (repository.isClosingTask(taskInfo.taskId)
+ && repository.removeClosingTask(taskInfo.taskId)) {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE,
+ "Removing closing freeform task: #%d", taskInfo.taskId);
}
repository.updateVisibleFreeformTasks(taskInfo.displayId, taskInfo.taskId,
taskInfo.isVisible);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java
index 202f60d..3d1994c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java
@@ -137,7 +137,7 @@
mTmpDestinationRect.inset(insets);
// Scale to the bounds no smaller than the destination and offset such that the top/left
// of the scaled inset source rect aligns with the top/left of the destination bounds
- final float scale, left, top;
+ final float scale;
if (isInPipDirection
&& sourceRectHint != null && sourceRectHint.width() < sourceBounds.width()) {
// scale by sourceRectHint if it's not edge-to-edge, for entering PiP transition only.
@@ -148,14 +148,17 @@
? (float) destinationBounds.width() / sourceBounds.width()
: (float) destinationBounds.height() / sourceBounds.height();
scale = (1 - fraction) * startScale + fraction * endScale;
- left = destinationBounds.left - insets.left * scale;
- top = destinationBounds.top - insets.top * scale;
} else {
scale = Math.max((float) destinationBounds.width() / sourceBounds.width(),
(float) destinationBounds.height() / sourceBounds.height());
- // Work around the rounding error by fix the position at very beginning.
- left = scale == 1 ? 0 : destinationBounds.left - insets.left * scale;
- top = scale == 1 ? 0 : destinationBounds.top - insets.top * scale;
+ }
+ float left = destinationBounds.left - insets.left * scale;
+ float top = destinationBounds.top - insets.top * scale;
+ if (scale == 1) {
+ // Work around the 1 pixel off error by rounding the position down at very beginning.
+ // We noticed such error from flicker tests, not visually.
+ left = sourceBounds.left;
+ top = sourceBounds.top;
}
mTmpTransform.setScale(scale, scale);
tx.setMatrix(leash, mTmpTransform, mTmpFloat9)
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index e4420d7..e2e1ecd 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -63,7 +63,6 @@
import android.graphics.Rect;
import android.os.RemoteException;
import android.os.SystemProperties;
-import android.util.Rational;
import android.view.Choreographer;
import android.view.Display;
import android.view.Surface;
@@ -128,8 +127,6 @@
SystemProperties.getInt(
"persist.wm.debug.extra_content_overlay_fade_out_delay_ms", 400);
- private static final float PIP_ASPECT_RATIO_MISMATCH_THRESHOLD = 0.005f;
-
private final Context mContext;
private final SyncTransactionQueue mSyncTransactionQueue;
private final PipBoundsState mPipBoundsState;
@@ -608,6 +605,7 @@
public void exitPip(int animationDurationMs, boolean requestEnterSplit) {
if (!mPipTransitionState.isInPip()
|| mPipTransitionState.getTransitionState() == PipTransitionState.EXITING_PIP
+ || mPipTransitionState.getInSwipePipToHomeTransition()
|| mToken == null) {
ProtoLog.wtf(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
"%s: Not allowed to exitPip in current state"
@@ -821,37 +819,6 @@
mPictureInPictureParams.getTitle());
mPipParamsChangedForwarder.notifySubtitleChanged(
mPictureInPictureParams.getSubtitle());
-
- if (mPictureInPictureParams.hasSourceBoundsHint()
- && mPictureInPictureParams.hasSetAspectRatio()) {
- Rational sourceRectHintAspectRatio = new Rational(
- mPictureInPictureParams.getSourceRectHint().width(),
- mPictureInPictureParams.getSourceRectHint().height());
- if (sourceRectHintAspectRatio.compareTo(
- mPictureInPictureParams.getAspectRatio()) != 0) {
- ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
- "Aspect ratio of source rect hint (%d/%d) does not match the provided "
- + "aspect ratio value (%d/%d). Consider matching them for "
- + "improved animation. Future releases might override the "
- + "value to match.",
- mPictureInPictureParams.getSourceRectHint().width(),
- mPictureInPictureParams.getSourceRectHint().height(),
- mPictureInPictureParams.getAspectRatio().getNumerator(),
- mPictureInPictureParams.getAspectRatio().getDenominator());
- }
- if (Math.abs(sourceRectHintAspectRatio.floatValue()
- - mPictureInPictureParams.getAspectRatioFloat())
- > PIP_ASPECT_RATIO_MISMATCH_THRESHOLD) {
- ProtoLog.w(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
- "Aspect ratio of source rect hint (%f) does not match the provided "
- + "aspect ratio value (%f) and is above threshold of %f. "
- + "Consider matching them for improved animation. Future "
- + "releases might override the value to match.",
- sourceRectHintAspectRatio.floatValue(),
- mPictureInPictureParams.getAspectRatioFloat(),
- PIP_ASPECT_RATIO_MISMATCH_THRESHOLD);
- }
- }
}
mPipUiEventLoggerLogger.setTaskInfo(mTaskInfo);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java
index 66b3553..8fc54ed 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java
@@ -21,8 +21,6 @@
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
-import static com.android.window.flags.Flags.windowSessionRelayoutInfo;
-
import android.annotation.BinderThread;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -30,7 +28,6 @@
import android.app.ActivityManager.TaskDescription;
import android.graphics.Paint;
import android.graphics.Rect;
-import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.Trace;
@@ -139,16 +136,10 @@
}
try {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "TaskSnapshot#relayout");
- if (windowSessionRelayoutInfo()) {
- final WindowRelayoutResult outRelayoutResult = new WindowRelayoutResult(tmpFrames,
- tmpMergedConfiguration, surfaceControl, tmpInsetsState, tmpControls);
- session.relayout(window, layoutParams, -1, -1, View.VISIBLE, 0, 0, 0,
- outRelayoutResult);
- } else {
- session.relayoutLegacy(window, layoutParams, -1, -1, View.VISIBLE, 0, 0, 0,
- tmpFrames, tmpMergedConfiguration, surfaceControl, tmpInsetsState,
- tmpControls, new Bundle());
- }
+ final WindowRelayoutResult outRelayoutResult = new WindowRelayoutResult(tmpFrames,
+ tmpMergedConfiguration, surfaceControl, tmpInsetsState, tmpControls);
+ session.relayout(window, layoutParams, -1, -1, View.VISIBLE, 0, 0, 0,
+ outRelayoutResult);
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
} catch (RemoteException e) {
snapshotSurface.clearWindowSynced();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
index 21b6db2..5e7e5e6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
@@ -435,7 +435,7 @@
SplitScreenController.EXIT_REASON_DESKTOP_MODE);
} else {
WindowContainerTransaction wct = new WindowContainerTransaction();
- mDesktopTasksController.onDesktopWindowClose(wct, mTaskId);
+ mDesktopTasksController.onDesktopWindowClose(wct, mDisplayId, mTaskId);
mTaskOperations.closeTask(mTaskToken, wct);
}
} else if (id == R.id.back_button) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositioner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositioner.java
index 5fce5d2..956d04c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositioner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositioner.java
@@ -18,6 +18,8 @@
import static android.view.WindowManager.TRANSIT_CHANGE;
+import static com.android.internal.jank.Cuj.CUJ_DESKTOP_MODE_RESIZE_WINDOW;
+
import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.Rect;
@@ -33,6 +35,7 @@
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.InteractionJankMonitorUtils;
import com.android.wm.shell.transition.Transitions;
import java.util.function.Supplier;
@@ -89,6 +92,10 @@
mDesktopWindowDecoration.mTaskInfo.configuration.windowConfiguration.getBounds());
mRepositionStartPoint.set(x, y);
if (isResizing()) {
+ // Capture CUJ for re-sizing window in DW mode.
+ InteractionJankMonitorUtils.beginTracing(CUJ_DESKTOP_MODE_RESIZE_WINDOW,
+ mDesktopWindowDecoration.mContext, mDesktopWindowDecoration.mTaskSurface,
+ /* tag= */ null);
if (!mDesktopWindowDecoration.mTaskInfo.isFocused) {
WindowContainerTransaction wct = new WindowContainerTransaction();
wct.reorder(mDesktopWindowDecoration.mTaskInfo.token, true);
@@ -146,6 +153,7 @@
// won't be called.
resetVeilIfVisible();
}
+ InteractionJankMonitorUtils.endTracing(CUJ_DESKTOP_MODE_RESIZE_WINDOW);
} else {
final WindowContainerTransaction wct = new WindowContainerTransaction();
DragPositioningCallbackUtility.updateTaskBounds(mRepositionTaskBounds,
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserverTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserverTest.kt
index cead21b..665bed0 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserverTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserverTest.kt
@@ -86,9 +86,7 @@
@JvmField
@Rule
val extendedMockitoRule =
- ExtendedMockitoRule.Builder(this)
- .mockStatic(DesktopModeStatus::class.java)
- .build()!!
+ ExtendedMockitoRule.Builder(this).mockStatic(DesktopModeStatus::class.java).build()!!
private val testExecutor = mock<ShellExecutor>()
private val mockShellInit = mock<ShellInit>()
@@ -222,7 +220,7 @@
callOnTransitionReady(previousTransitionInfo)
verifyTaskRemovedAndExitLogging(
- previousSessionId, ExitReason.RETURN_HOME_OR_OVERVIEW, DEFAULT_TASK_UPDATE)
+ previousSessionId, ExitReason.RETURN_HOME_OR_OVERVIEW, DEFAULT_TASK_UPDATE)
// Enter desktop mode from cancelled recents has no transition. Enter is detected on the
// next transition involving freeform windows
@@ -252,7 +250,7 @@
callOnTransitionReady(previousTransitionInfo)
verifyTaskRemovedAndExitLogging(
- previousSessionId, ExitReason.RETURN_HOME_OR_OVERVIEW, DEFAULT_TASK_UPDATE)
+ previousSessionId, ExitReason.RETURN_HOME_OR_OVERVIEW, DEFAULT_TASK_UPDATE)
// Enter desktop mode from cancelled recents has no transition. Enter is detected on the
// next transition involving freeform windows
@@ -282,7 +280,7 @@
callOnTransitionReady(previousTransitionInfo)
verifyTaskRemovedAndExitLogging(
- previousSessionId, ExitReason.RETURN_HOME_OR_OVERVIEW, DEFAULT_TASK_UPDATE)
+ previousSessionId, ExitReason.RETURN_HOME_OR_OVERVIEW, DEFAULT_TASK_UPDATE)
// Enter desktop mode from cancelled recents has no transition. Enter is detected on the
// next transition involving freeform windows
@@ -308,21 +306,21 @@
transitionObserver.addTaskInfosToCachedMap(previousTaskInfo)
transitionObserver.setLoggerSessionId(previousSessionId)
val previousTransitionInfo =
- TransitionInfoBuilder(TRANSIT_TO_FRONT, TRANSIT_FLAG_IS_RECENTS)
- .addChange(createChange(TRANSIT_TO_BACK, previousTaskInfo))
- .build()
+ TransitionInfoBuilder(TRANSIT_TO_FRONT, TRANSIT_FLAG_IS_RECENTS)
+ .addChange(createChange(TRANSIT_TO_BACK, previousTaskInfo))
+ .build()
callOnTransitionReady(previousTransitionInfo)
verifyTaskRemovedAndExitLogging(
- previousSessionId, ExitReason.RETURN_HOME_OR_OVERVIEW, DEFAULT_TASK_UPDATE)
+ previousSessionId, ExitReason.RETURN_HOME_OR_OVERVIEW, DEFAULT_TASK_UPDATE)
// TRANSIT_ENTER_DESKTOP_FROM_APP_FROM_OVERVIEW
val change = createChange(TRANSIT_TO_FRONT, createTaskInfo(WINDOWING_MODE_FREEFORM))
val transitionInfo =
- TransitionInfoBuilder(TRANSIT_ENTER_DESKTOP_FROM_APP_FROM_OVERVIEW, 0)
- .addChange(change)
- .build()
+ TransitionInfoBuilder(TRANSIT_ENTER_DESKTOP_FROM_APP_FROM_OVERVIEW, 0)
+ .addChange(change)
+ .build()
callOnTransitionReady(transitionInfo)
@@ -504,6 +502,105 @@
}
@Test
+ fun sessionAlreadyStarted_taskPositionChanged_logsTaskUpdate() {
+ val sessionId = 1
+ // add an existing freeform task
+ val taskInfo = createTaskInfo(WINDOWING_MODE_FREEFORM)
+ transitionObserver.addTaskInfosToCachedMap(taskInfo)
+ transitionObserver.setLoggerSessionId(sessionId)
+
+ // task position changed
+ val newTaskInfo = createTaskInfo(WINDOWING_MODE_FREEFORM, taskX = DEFAULT_TASK_X + 100)
+ val transitionInfo =
+ TransitionInfoBuilder(TRANSIT_CHANGE, 0)
+ .addChange(createChange(TRANSIT_CHANGE, newTaskInfo))
+ .build()
+ callOnTransitionReady(transitionInfo)
+
+ verify(desktopModeEventLogger, times(1))
+ .logTaskInfoChanged(
+ eq(sessionId), eq(DEFAULT_TASK_UPDATE.copy(taskX = DEFAULT_TASK_X + 100)))
+ verifyZeroInteractions(desktopModeEventLogger)
+ }
+
+ @Test
+ fun sessionAlreadyStarted_taskResized_logsTaskUpdate() {
+ val sessionId = 1
+ // add an existing freeform task
+ val taskInfo = createTaskInfo(WINDOWING_MODE_FREEFORM)
+ transitionObserver.addTaskInfosToCachedMap(taskInfo)
+ transitionObserver.setLoggerSessionId(sessionId)
+
+ // task resized
+ val newTaskInfo =
+ createTaskInfo(
+ WINDOWING_MODE_FREEFORM,
+ taskWidth = DEFAULT_TASK_WIDTH + 100,
+ taskHeight = DEFAULT_TASK_HEIGHT - 100)
+ val transitionInfo =
+ TransitionInfoBuilder(TRANSIT_CHANGE, 0)
+ .addChange(createChange(TRANSIT_CHANGE, newTaskInfo))
+ .build()
+ callOnTransitionReady(transitionInfo)
+
+ verify(desktopModeEventLogger, times(1))
+ .logTaskInfoChanged(
+ eq(sessionId),
+ eq(
+ DEFAULT_TASK_UPDATE.copy(
+ taskWidth = DEFAULT_TASK_WIDTH + 100, taskHeight = DEFAULT_TASK_HEIGHT - 100)))
+ verifyZeroInteractions(desktopModeEventLogger)
+ }
+
+ @Test
+ fun sessionAlreadyStarted_multipleTasksUpdated_logsTaskUpdateForCorrectTask() {
+ val sessionId = 1
+ // add 2 existing freeform task
+ val taskInfo1 = createTaskInfo(WINDOWING_MODE_FREEFORM)
+ val taskInfo2 = createTaskInfo(WINDOWING_MODE_FREEFORM, id = 2)
+ transitionObserver.addTaskInfosToCachedMap(taskInfo1)
+ transitionObserver.addTaskInfosToCachedMap(taskInfo2)
+ transitionObserver.setLoggerSessionId(sessionId)
+
+ // task 1 position update
+ val newTaskInfo1 = createTaskInfo(WINDOWING_MODE_FREEFORM, taskX = DEFAULT_TASK_X + 100)
+ val transitionInfo1 =
+ TransitionInfoBuilder(TRANSIT_CHANGE, 0)
+ .addChange(createChange(TRANSIT_CHANGE, newTaskInfo1))
+ .build()
+ callOnTransitionReady(transitionInfo1)
+
+ verify(desktopModeEventLogger, times(1))
+ .logTaskInfoChanged(
+ eq(sessionId), eq(DEFAULT_TASK_UPDATE.copy(taskX = DEFAULT_TASK_X + 100)))
+ verifyZeroInteractions(desktopModeEventLogger)
+
+ // task 2 resize
+ val newTaskInfo2 =
+ createTaskInfo(
+ WINDOWING_MODE_FREEFORM,
+ id = 2,
+ taskWidth = DEFAULT_TASK_WIDTH + 100,
+ taskHeight = DEFAULT_TASK_HEIGHT - 100)
+ val transitionInfo2 =
+ TransitionInfoBuilder(TRANSIT_CHANGE, 0)
+ .addChange(createChange(TRANSIT_CHANGE, newTaskInfo2))
+ .build()
+
+ callOnTransitionReady(transitionInfo2)
+
+ verify(desktopModeEventLogger, times(1))
+ .logTaskInfoChanged(
+ eq(sessionId),
+ eq(
+ DEFAULT_TASK_UPDATE.copy(
+ instanceId = 2,
+ taskWidth = DEFAULT_TASK_WIDTH + 100,
+ taskHeight = DEFAULT_TASK_HEIGHT - 100)))
+ verifyZeroInteractions(desktopModeEventLogger)
+ }
+
+ @Test
fun sessionAlreadyStarted_freeformTaskRemoved_logsTaskRemoved() {
val sessionId = 1
// add two existing freeform tasks
@@ -564,7 +661,7 @@
DEFAULT_TASK_WIDTH,
DEFAULT_TASK_X,
DEFAULT_TASK_Y,
- )
+ )
fun createTaskInfo(
windowMode: Int,
@@ -574,15 +671,16 @@
taskWidth: Int = DEFAULT_TASK_WIDTH,
taskX: Int = DEFAULT_TASK_X,
taskY: Int = DEFAULT_TASK_Y,
- ) = ActivityManager.RunningTaskInfo().apply {
+ ) =
+ ActivityManager.RunningTaskInfo().apply {
taskId = id
userId = uid
configuration.windowConfiguration.apply {
windowingMode = windowMode
positionInParent = Point(taskX, taskY)
bounds.set(Rect(taskX, taskY, taskX + taskWidth, taskY + taskHeight))
+ }
}
- }
fun createChange(mode: Int, taskInfo: ActivityManager.RunningTaskInfo): Change {
val change =
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepositoryTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepositoryTest.kt
index 310ccc2..193d614 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepositoryTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepositoryTest.kt
@@ -119,54 +119,86 @@
}
@Test
- fun isOnlyActiveTask_noActiveTasks() {
+ fun isOnlyActiveNonClosingTask_noActiveNonClosingTasks() {
// Not an active task
- assertThat(repo.isOnlyActiveTask(1)).isFalse()
+ assertThat(repo.isOnlyActiveNonClosingTask(1)).isFalse()
+ assertThat(repo.isClosingTask(1)).isFalse()
}
@Test
- fun isOnlyActiveTask_singleActiveTask() {
+ fun isOnlyActiveNonClosingTask_singleActiveNonClosingTask() {
repo.addActiveTask(DEFAULT_DISPLAY, 1)
// The only active task
assertThat(repo.isActiveTask(1)).isTrue()
- assertThat(repo.isOnlyActiveTask(1)).isTrue()
+ assertThat(repo.isClosingTask(1)).isFalse()
+ assertThat(repo.isOnlyActiveNonClosingTask(1)).isTrue()
// Not an active task
assertThat(repo.isActiveTask(99)).isFalse()
- assertThat(repo.isOnlyActiveTask(99)).isFalse()
+ assertThat(repo.isClosingTask(99)).isFalse()
+ assertThat(repo.isOnlyActiveNonClosingTask(99)).isFalse()
}
@Test
- fun isOnlyActiveTask_multipleActiveTasks() {
+ fun isOnlyActiveNonClosingTask_singleActiveClosingTask() {
+ repo.addActiveTask(DEFAULT_DISPLAY, 1)
+ repo.addClosingTask(DEFAULT_DISPLAY, 1)
+ // The active task that's closing
+ assertThat(repo.isActiveTask(1)).isTrue()
+ assertThat(repo.isClosingTask(1)).isTrue()
+ assertThat(repo.isOnlyActiveNonClosingTask(1)).isFalse()
+ // Not an active task
+ assertThat(repo.isActiveTask(99)).isFalse()
+ assertThat(repo.isOnlyActiveNonClosingTask(99)).isFalse()
+ }
+
+ @Test
+ fun isOnlyActiveNonClosingTask_singleActiveMinimizedTask() {
+ repo.addActiveTask(DEFAULT_DISPLAY, 1)
+ repo.minimizeTask(DEFAULT_DISPLAY, 1)
+ // The active task that's closing
+ assertThat(repo.isActiveTask(1)).isTrue()
+ assertThat(repo.isMinimizedTask(1)).isTrue()
+ assertThat(repo.isOnlyActiveNonClosingTask(1)).isFalse()
+ // Not an active task
+ assertThat(repo.isActiveTask(99)).isFalse()
+ assertThat(repo.isOnlyActiveNonClosingTask(99)).isFalse()
+ }
+
+ @Test
+ fun isOnlyActiveNonClosingTask_multipleActiveNonClosingTasks() {
repo.addActiveTask(DEFAULT_DISPLAY, 1)
repo.addActiveTask(DEFAULT_DISPLAY, 2)
// Not the only task
assertThat(repo.isActiveTask(1)).isTrue()
- assertThat(repo.isOnlyActiveTask(1)).isFalse()
+ assertThat(repo.isClosingTask(1)).isFalse()
+ assertThat(repo.isOnlyActiveNonClosingTask(1)).isFalse()
// Not the only task
assertThat(repo.isActiveTask(2)).isTrue()
- assertThat(repo.isOnlyActiveTask(2)).isFalse()
+ assertThat(repo.isClosingTask(2)).isFalse()
+ assertThat(repo.isOnlyActiveNonClosingTask(2)).isFalse()
// Not an active task
assertThat(repo.isActiveTask(99)).isFalse()
- assertThat(repo.isOnlyActiveTask(99)).isFalse()
+ assertThat(repo.isClosingTask(99)).isFalse()
+ assertThat(repo.isOnlyActiveNonClosingTask(99)).isFalse()
}
@Test
- fun isOnlyActiveTask_multipleDisplays() {
+ fun isOnlyActiveNonClosingTask_multipleDisplays() {
repo.addActiveTask(DEFAULT_DISPLAY, 1)
repo.addActiveTask(DEFAULT_DISPLAY, 2)
repo.addActiveTask(SECOND_DISPLAY, 3)
// Not the only task on DEFAULT_DISPLAY
assertThat(repo.isActiveTask(1)).isTrue()
- assertThat(repo.isOnlyActiveTask(1)).isFalse()
+ assertThat(repo.isOnlyActiveNonClosingTask(1)).isFalse()
// Not the only task on DEFAULT_DISPLAY
assertThat(repo.isActiveTask(2)).isTrue()
- assertThat(repo.isOnlyActiveTask(2)).isFalse()
+ assertThat(repo.isOnlyActiveNonClosingTask(2)).isFalse()
// The only active task on SECOND_DISPLAY
assertThat(repo.isActiveTask(3)).isTrue()
- assertThat(repo.isOnlyActiveTask(3)).isTrue()
+ assertThat(repo.isOnlyActiveNonClosingTask(3)).isTrue()
// Not an active task
assertThat(repo.isActiveTask(99)).isFalse()
- assertThat(repo.isOnlyActiveTask(99)).isFalse()
+ assertThat(repo.isOnlyActiveNonClosingTask(99)).isFalse()
}
@Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
index e17f7f2..392161f 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
@@ -923,7 +923,7 @@
@Test
fun onDesktopWindowClose_noActiveTasks() {
val wct = WindowContainerTransaction()
- controller.onDesktopWindowClose(wct, 1 /* taskId */)
+ controller.onDesktopWindowClose(wct, displayId = DEFAULT_DISPLAY, taskId = 1)
// Doesn't modify transaction
assertThat(wct.hierarchyOps).isEmpty()
}
@@ -932,7 +932,7 @@
fun onDesktopWindowClose_singleActiveTask_noWallpaperActivityToken() {
val task = setUpFreeformTask()
val wct = WindowContainerTransaction()
- controller.onDesktopWindowClose(wct, task.taskId)
+ controller.onDesktopWindowClose(wct, displayId = DEFAULT_DISPLAY, taskId = task.taskId)
// Doesn't modify transaction
assertThat(wct.hierarchyOps).isEmpty()
}
@@ -944,12 +944,38 @@
desktopModeTaskRepository.wallpaperActivityToken = wallpaperToken
val wct = WindowContainerTransaction()
- controller.onDesktopWindowClose(wct, task.taskId)
+ controller.onDesktopWindowClose(wct, displayId = DEFAULT_DISPLAY, taskId = task.taskId)
// Adds remove wallpaper operation
wct.assertRemoveAt(index = 0, wallpaperToken)
}
@Test
+ fun onDesktopWindowClose_singleActiveTask_isClosing() {
+ val task = setUpFreeformTask()
+ val wallpaperToken = MockToken().token()
+ desktopModeTaskRepository.wallpaperActivityToken = wallpaperToken
+ desktopModeTaskRepository.addClosingTask(DEFAULT_DISPLAY, task.taskId)
+
+ val wct = WindowContainerTransaction()
+ controller.onDesktopWindowClose(wct, displayId = DEFAULT_DISPLAY, taskId = task.taskId)
+ // Doesn't modify transaction
+ assertThat(wct.hierarchyOps).isEmpty()
+ }
+
+ @Test
+ fun onDesktopWindowClose_singleActiveTask_isMinimized() {
+ val task = setUpFreeformTask()
+ val wallpaperToken = MockToken().token()
+ desktopModeTaskRepository.wallpaperActivityToken = wallpaperToken
+ desktopModeTaskRepository.minimizeTask(DEFAULT_DISPLAY, task.taskId)
+
+ val wct = WindowContainerTransaction()
+ controller.onDesktopWindowClose(wct, displayId = DEFAULT_DISPLAY, taskId = task.taskId)
+ // Doesn't modify transaction
+ assertThat(wct.hierarchyOps).isEmpty()
+ }
+
+ @Test
fun onDesktopWindowClose_multipleActiveTasks() {
val task1 = setUpFreeformTask()
setUpFreeformTask()
@@ -957,12 +983,40 @@
desktopModeTaskRepository.wallpaperActivityToken = wallpaperToken
val wct = WindowContainerTransaction()
- controller.onDesktopWindowClose(wct, task1.taskId)
+ controller.onDesktopWindowClose(wct, displayId = DEFAULT_DISPLAY, taskId = task1.taskId)
// Doesn't modify transaction
assertThat(wct.hierarchyOps).isEmpty()
}
@Test
+ fun onDesktopWindowClose_multipleActiveTasks_isOnlyNonClosingTask() {
+ val task1 = setUpFreeformTask()
+ val task2 = setUpFreeformTask()
+ val wallpaperToken = MockToken().token()
+ desktopModeTaskRepository.wallpaperActivityToken = wallpaperToken
+ desktopModeTaskRepository.addClosingTask(DEFAULT_DISPLAY, task2.taskId)
+
+ val wct = WindowContainerTransaction()
+ controller.onDesktopWindowClose(wct, displayId = DEFAULT_DISPLAY, taskId = task1.taskId)
+ // Adds remove wallpaper operation
+ wct.assertRemoveAt(index = 0, wallpaperToken)
+ }
+
+ @Test
+ fun onDesktopWindowClose_multipleActiveTasks_hasMinimized() {
+ val task1 = setUpFreeformTask()
+ val task2 = setUpFreeformTask()
+ val wallpaperToken = MockToken().token()
+ desktopModeTaskRepository.wallpaperActivityToken = wallpaperToken
+ desktopModeTaskRepository.minimizeTask(DEFAULT_DISPLAY, task2.taskId)
+
+ val wct = WindowContainerTransaction()
+ controller.onDesktopWindowClose(wct, displayId = DEFAULT_DISPLAY, taskId = task1.taskId)
+ // Adds remove wallpaper operation
+ wct.assertRemoveAt(index = 0, wallpaperToken)
+ }
+
+ @Test
fun handleRequest_fullscreenTask_freeformVisible_returnSwitchToFreeformWCT() {
assumeTrue(ENABLE_SHELL_TRANSITIONS)
@@ -1245,6 +1299,30 @@
}
@Test
+ @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY)
+ fun handleRequest_backTransition_multipleActiveTasks_singleNonClosing() {
+ desktopModeTaskRepository.wallpaperActivityToken = MockToken().token()
+
+ val task1 = setUpFreeformTask()
+ setUpFreeformTask()
+ val result = controller.handleRequest(Binder(), createTransition(task1, type = TRANSIT_TO_BACK))
+ // Doesn't handle request
+ assertThat(result).isNull()
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY)
+ fun handleRequest_backTransition_multipleActiveTasks_singleNonMinimized() {
+ desktopModeTaskRepository.wallpaperActivityToken = MockToken().token()
+
+ val task1 = setUpFreeformTask()
+ setUpFreeformTask()
+ val result = controller.handleRequest(Binder(), createTransition(task1, type = TRANSIT_TO_BACK))
+ // Doesn't handle request
+ assertThat(result).isNull()
+ }
+
+ @Test
fun desktopTasksVisibilityChange_visible_setLaunchAdjacentDisabled() {
val task = setUpFreeformTask()
clearInvocations(launchAdjacentController)
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipAnimationControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipAnimationControllerTest.java
index 5880ffb..72950a8 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipAnimationControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipAnimationControllerTest.java
@@ -88,8 +88,11 @@
@Test
public void getAnimator_withBounds_returnBoundsAnimator() {
+ final Rect baseValue = new Rect(0, 0, 100, 100);
+ final Rect startValue = new Rect(0, 0, 100, 100);
+ final Rect endValue1 = new Rect(100, 100, 200, 200);
final PipAnimationController.PipTransitionAnimator animator = mPipAnimationController
- .getAnimator(mTaskInfo, mLeash, new Rect(), new Rect(), new Rect(), null,
+ .getAnimator(mTaskInfo, mLeash, baseValue, startValue, endValue1, null,
TRANSITION_DIRECTION_TO_PIP, 0, ROTATION_0);
assertEquals("Expect ANIM_TYPE_BOUNDS animation",
diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp
index 0d0af11..4d185c6 100644
--- a/libs/hwui/renderthread/VulkanManager.cpp
+++ b/libs/hwui/renderthread/VulkanManager.cpp
@@ -28,8 +28,8 @@
#include <include/gpu/ganesh/vk/GrVkBackendSemaphore.h>
#include <include/gpu/ganesh/vk/GrVkBackendSurface.h>
#include <include/gpu/ganesh/vk/GrVkDirectContext.h>
+#include <include/gpu/vk/VulkanBackendContext.h>
#include <ui/FatVector.h>
-#include <vk/GrVkExtensions.h>
#include <vk/GrVkTypes.h>
#include <sstream>
@@ -141,7 +141,8 @@
mPhysicalDeviceFeatures2 = {};
}
-void VulkanManager::setupDevice(GrVkExtensions& grExtensions, VkPhysicalDeviceFeatures2& features) {
+void VulkanManager::setupDevice(skgpu::VulkanExtensions& grExtensions,
+ VkPhysicalDeviceFeatures2& features) {
VkResult err;
constexpr VkApplicationInfo app_info = {
@@ -506,7 +507,7 @@
return vkGetInstanceProcAddr(instance, proc_name);
};
- GrVkBackendContext backendContext;
+ skgpu::VulkanBackendContext backendContext;
backendContext.fInstance = mInstance;
backendContext.fPhysicalDevice = mPhysicalDevice;
backendContext.fDevice = mDevice;
diff --git a/libs/hwui/renderthread/VulkanManager.h b/libs/hwui/renderthread/VulkanManager.h
index b92ebb3..08f9d42 100644
--- a/libs/hwui/renderthread/VulkanManager.h
+++ b/libs/hwui/renderthread/VulkanManager.h
@@ -24,8 +24,7 @@
#include <SkSurface.h>
#include <android-base/unique_fd.h>
#include <utils/StrongPointer.h>
-#include <vk/GrVkBackendContext.h>
-#include <vk/GrVkExtensions.h>
+#include <vk/VulkanExtensions.h>
#include <vulkan/vulkan.h>
// VK_ANDROID_frame_boundary is a bespoke extension defined by AGI
@@ -127,7 +126,7 @@
// Sets up the VkInstance and VkDevice objects. Also fills out the passed in
// VkPhysicalDeviceFeatures struct.
- void setupDevice(GrVkExtensions&, VkPhysicalDeviceFeatures2&);
+ void setupDevice(skgpu::VulkanExtensions&, VkPhysicalDeviceFeatures2&);
// simple wrapper class that exists only to initialize a pointer to NULL
template <typename FNPTR_TYPE>
@@ -206,7 +205,7 @@
BufferAge,
};
SwapBehavior mSwapBehavior = SwapBehavior::Discard;
- GrVkExtensions mExtensions;
+ skgpu::VulkanExtensions mExtensions;
uint32_t mDriverVersion = 0;
std::once_flag mInitFlag;
diff --git a/lint-baseline.xml b/lint-baseline.xml
index 660884a..0320aab 100644
--- a/lint-baseline.xml
+++ b/lint-baseline.xml
@@ -562,4 +562,10707 @@
column="74"/>
</issue>
+ <issue
+ id="FlaggedApi"
+ message="Method `getItemCount()` is a flagged API and should be inside an `if (Flags.collectionInfoItemCounts())` check (or annotate the surrounding method `writeToParcelNoRecycle` with `@FlaggedApi(Flags.FLAG_COLLECTION_INFO_ITEM_COUNTS) to transfer requirement to caller`)"
+ errorLine1=" parcel.writeInt(mCollectionInfo.getItemCount());"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/view/accessibility/AccessibilityNodeInfo.java"
+ line="4498"
+ column="29"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `getImportantForAccessibilityItemCount()` is a flagged API and should be inside an `if (Flags.collectionInfoItemCounts())` check (or annotate the surrounding method `writeToParcelNoRecycle` with `@FlaggedApi(Flags.FLAG_COLLECTION_INFO_ITEM_COUNTS) to transfer requirement to caller`)"
+ errorLine1=" parcel.writeInt(mCollectionInfo.getImportantForAccessibilityItemCount());"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/view/accessibility/AccessibilityNodeInfo.java"
+ line="4499"
+ column="29"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `isGranularScrollingSupported()` is a flagged API and should be inside an `if (Flags.granularScrolling())` check (or annotate the surrounding method `toString` with `@FlaggedApi(Flags.FLAG_GRANULAR_SCROLLING) to transfer requirement to caller`)"
+ errorLine1=" builder.append("; granularScrollingSupported: ").append(isGranularScrollingSupported());"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/view/accessibility/AccessibilityNodeInfo.java"
+ line="5079"
+ column="65"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `UNDEFINED` is a flagged API and should be inside an `if (Flags.collectionInfoItemCounts())` check (or annotate the surrounding method `CollectionInfo` with `@FlaggedApi(Flags.FLAG_COLLECTION_INFO_ITEM_COUNTS) to transfer requirement to caller`)"
+ errorLine1=" mItemCount = UNDEFINED;"
+ errorLine2=" ~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/view/accessibility/AccessibilityNodeInfo.java"
+ line="6211"
+ column="26"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `UNDEFINED` is a flagged API and should be inside an `if (Flags.collectionInfoItemCounts())` check (or annotate the surrounding method `CollectionInfo` with `@FlaggedApi(Flags.FLAG_COLLECTION_INFO_ITEM_COUNTS) to transfer requirement to caller`)"
+ errorLine1=" mImportantForAccessibilityItemCount = UNDEFINED;"
+ errorLine2=" ~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/view/accessibility/AccessibilityNodeInfo.java"
+ line="6212"
+ column="51"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `UNDEFINED` is a flagged API and should be inside an `if (Flags.collectionInfoItemCounts())` check (or annotate the surrounding method `clear` with `@FlaggedApi(Flags.FLAG_COLLECTION_INFO_ITEM_COUNTS) to transfer requirement to caller`)"
+ errorLine1=" mItemCount = UNDEFINED;"
+ errorLine2=" ~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/view/accessibility/AccessibilityNodeInfo.java"
+ line="6319"
+ column="26"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `UNDEFINED` is a flagged API and should be inside an `if (Flags.collectionInfoItemCounts())` check (or annotate the surrounding method `clear` with `@FlaggedApi(Flags.FLAG_COLLECTION_INFO_ITEM_COUNTS) to transfer requirement to caller`)"
+ errorLine1=" mImportantForAccessibilityItemCount = UNDEFINED;"
+ errorLine2=" ~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/view/accessibility/AccessibilityNodeInfo.java"
+ line="6320"
+ column="51"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @FlaggedApi("android.view.accessibility.a11y_overlay_callbacks")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/accessibilityservice/AccessibilityService.java"
+ line="800"
+ column="17"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @FlaggedApi("android.view.accessibility.a11y_overlay_callbacks")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/accessibilityservice/AccessibilityService.java"
+ line="811"
+ column="17"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @FlaggedApi("android.view.accessibility.a11y_overlay_callbacks")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/accessibilityservice/AccessibilityService.java"
+ line="811"
+ column="17"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @FlaggedApi("android.view.accessibility.a11y_overlay_callbacks")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/accessibilityservice/AccessibilityService.java"
+ line="811"
+ column="17"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @FlaggedApi("android.view.accessibility.a11y_overlay_callbacks")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/accessibilityservice/AccessibilityService.java"
+ line="819"
+ column="17"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @FlaggedApi("android.view.accessibility.a11y_overlay_callbacks")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/accessibilityservice/AccessibilityService.java"
+ line="819"
+ column="17"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @FlaggedApi("android.view.accessibility.a11y_overlay_callbacks")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/accessibilityservice/AccessibilityService.java"
+ line="819"
+ column="17"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @FlaggedApi("android.view.accessibility.a11y_overlay_callbacks")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/accessibilityservice/AccessibilityService.java"
+ line="819"
+ column="17"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @FlaggedApi("android.view.accessibility.a11y_overlay_callbacks")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/accessibilityservice/AccessibilityService.java"
+ line="819"
+ column="17"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @FlaggedApi("android.view.accessibility.a11y_overlay_callbacks")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/accessibilityservice/AccessibilityService.java"
+ line="819"
+ column="17"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @FlaggedApi("android.view.accessibility.a11y_overlay_callbacks")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/accessibilityservice/AccessibilityService.java"
+ line="819"
+ column="17"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @FlaggedApi("android.view.accessibility.a11y_overlay_callbacks")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/accessibilityservice/AccessibilityService.java"
+ line="827"
+ column="17"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @FlaggedApi("android.view.accessibility.a11y_overlay_callbacks")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/accessibilityservice/AccessibilityService.java"
+ line="827"
+ column="17"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `setObservedMotionEventSources()` is a flagged API and should be inside an `if (Flags.motionEventObserving())` check (or annotate the surrounding method `initFromParcel` with `@FlaggedApi(Flags.FLAG_MOTION_EVENT_OBSERVING) to transfer requirement to caller`)"
+ errorLine1=" setObservedMotionEventSources(parcel.readInt());"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/accessibilityservice/AccessibilityServiceInfo.java"
+ line="1420"
+ column="9"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `TYPE_WINDOW_CONTROL` is a flagged API and should be inside an `if (Flags.addTypeWindowControl())` check (or annotate the surrounding method `typeToString` with `@FlaggedApi(Flags.FLAG_ADD_TYPE_WINDOW_CONTROL) to transfer requirement to caller`)"
+ errorLine1=" if (Flags.addTypeWindowControl() && type == TYPE_WINDOW_CONTROL) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/view/accessibility/AccessibilityWindowInfo.java"
+ line="883"
+ column="53"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `requestPermissions()` is a flagged API and should be inside an `if (Flags.deviceAwarePermissionApisEnabled())` check (or annotate the surrounding method `requestPermissions` with `@FlaggedApi(Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED) to transfer requirement to caller`)"
+ errorLine1=" requestPermissions(permissions, requestCode, getDeviceId());"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/app/Activity.java"
+ line="5636"
+ column="9"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `EXTRA_REQUEST_PERMISSIONS_DEVICE_ID` is a flagged API and should be inside an `if (Flags.deviceAwarePermissionApisEnabled())` check (or annotate the surrounding method `dispatchRequestPermissionsResult` with `@FlaggedApi(Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED) to transfer requirement to caller`)"
+ errorLine1=" PackageManager.EXTRA_REQUEST_PERMISSIONS_DEVICE_ID, Context.DEVICE_ID_DEFAULT"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/app/Activity.java"
+ line="9530"
+ column="32"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `onRequestPermissionsResult()` is a flagged API and should be inside an `if (Flags.deviceAwarePermissionApisEnabled())` check (or annotate the surrounding method `dispatchRequestPermissionsResult` with `@FlaggedApi(Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED) to transfer requirement to caller`)"
+ errorLine1=" onRequestPermissionsResult(requestCode, permissions, grantResults, deviceId);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/app/Activity.java"
+ line="9532"
+ column="9"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `uptimeNanos()` is a flagged API and should be inside an `if (Flags.adpfGpuReportActualWorkDuration())` check (or annotate the surrounding method `handleBindApplication` with `@FlaggedApi(Flags.FLAG_ADPF_GPU_REPORT_ACTUAL_WORK_DURATION) to transfer requirement to caller`)"
+ errorLine1=" timestampApplicationOnCreateNs = SystemClock.uptimeNanos();"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/app/ActivityThread.java"
+ line="7503"
+ column="50"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `SeServiceManager()` is a flagged API and should be inside an `if (Flags.enableNfcMainline())` check (or annotate the surrounding method `initializeMainlineModules` with `@FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE) to transfer requirement to caller`)"
+ errorLine1=" SeFrameworkInitializer.setSeServiceManager(new SeServiceManager());"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/app/ActivityThread.java"
+ line="8725"
+ column="52"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `setSeServiceManager()` is a flagged API and should be inside an `if (Flags.enableNfcMainline())` check (or annotate the surrounding method `initializeMainlineModules` with `@FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE) to transfer requirement to caller`)"
+ errorLine1=" SeFrameworkInitializer.setSeServiceManager(new SeServiceManager());"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/app/ActivityThread.java"
+ line="8725"
+ column="9"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `ProfilingServiceManager()` is a flagged API and should be inside an `if (Flags.telemetryApisFrameworkInitialization())` check (or annotate the surrounding method `initializeMainlineModules` with `@FlaggedApi(Flags.FLAG_TELEMETRY_APIS_FRAMEWORK_INITIALIZATION) to transfer requirement to caller`)"
+ errorLine1=" ProfilingFrameworkInitializer.setProfilingServiceManager(new ProfilingServiceManager());"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/app/ActivityThread.java"
+ line="8727"
+ column="70"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `TvExtender()` is a flagged API and should be inside an `if (Flags.apiTvextender())` check (or annotate the surrounding method `createNotification` with `@FlaggedApi(Flags.FLAG_API_TVEXTENDER) to transfer requirement to caller`)"
+ errorLine1=" .extend(new Notification.TvExtender()"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/debug/AdbNotifications.java"
+ line="95"
+ column="25"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `setChannelId()` is a flagged API and should be inside an `if (Flags.apiTvextender())` check (or annotate the surrounding method `createNotification` with `@FlaggedApi(Flags.FLAG_API_TVEXTENDER) to transfer requirement to caller`)"
+ errorLine1=" .extend(new Notification.TvExtender()"
+ errorLine2=" ^">
+ <location
+ file="frameworks/base/core/java/android/debug/AdbNotifications.java"
+ line="95"
+ column="25"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `isMgf1DigestsSpecified()` is a flagged API and should be inside an `if (Flags.mgf1DigestSetterV2())` check (or annotate the surrounding method `initialize` with `@FlaggedApi(Flags.FLAG_MGF1_DIGEST_SETTER_V2) to transfer requirement to caller`)"
+ errorLine1=" if (spec.isMgf1DigestsSpecified()) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java"
+ line="346"
+ column="21"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `getMgf1Digests()` is a flagged API and should be inside an `if (Flags.mgf1DigestSetterV2())` check (or annotate the surrounding method `initialize` with `@FlaggedApi(Flags.FLAG_MGF1_DIGEST_SETTER_V2) to transfer requirement to caller`)"
+ errorLine1=" Set<String> mgfDigests = spec.getMgf1Digests();"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java"
+ line="349"
+ column="46"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `isMgf1DigestsSpecified()` is a flagged API and should be inside an `if (Flags.mgf1DigestSetterV2())` check (or annotate the surrounding method `setPrivateKeyEntry` with `@FlaggedApi(Flags.FLAG_MGF1_DIGEST_SETTER_V2) to transfer requirement to caller`)"
+ errorLine1=" if (spec.isMgf1DigestsSpecified()) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java"
+ line="539"
+ column="25"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `getMgf1Digests()` is a flagged API and should be inside an `if (Flags.mgf1DigestSetterV2())` check (or annotate the surrounding method `setPrivateKeyEntry` with `@FlaggedApi(Flags.FLAG_MGF1_DIGEST_SETTER_V2) to transfer requirement to caller`)"
+ errorLine1=" for (String mgf1Digest : spec.getMgf1Digests()) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java"
+ line="540"
+ column="50"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `TYPE_RCS_STRING` is a flagged API and should be inside an `if (Flags.carrierEnabledSatelliteFlag())` check (or annotate the surrounding method `?` with `@FlaggedApi(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG) to transfer requirement to caller`)"
+ errorLine1=" APN_TYPE_STRING_MAP.put(TYPE_RCS_STRING, TYPE_RCS);"
+ errorLine2=" ~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/data/ApnSetting.java"
+ line="491"
+ column="33"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `TYPE_RCS` is a flagged API and should be inside an `if (Flags.carrierEnabledSatelliteFlag())` check (or annotate the surrounding method `?` with `@FlaggedApi(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG) to transfer requirement to caller`)"
+ errorLine1=" APN_TYPE_STRING_MAP.put(TYPE_RCS_STRING, TYPE_RCS);"
+ errorLine2=" ~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/data/ApnSetting.java"
+ line="491"
+ column="50"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `TYPE_RCS_STRING` is a flagged API and should be inside an `if (Flags.carrierEnabledSatelliteFlag())` check (or annotate the surrounding method `?` with `@FlaggedApi(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG) to transfer requirement to caller`)"
+ errorLine1=" APN_TYPE_INT_MAP.put(TYPE_RCS, TYPE_RCS_STRING);"
+ errorLine2=" ~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/data/ApnSetting.java"
+ line="509"
+ column="40"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `TYPE_RCS` is a flagged API and should be inside an `if (Flags.carrierEnabledSatelliteFlag())` check (or annotate the surrounding method `?` with `@FlaggedApi(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG) to transfer requirement to caller`)"
+ errorLine1=" APN_TYPE_INT_MAP.put(TYPE_RCS, TYPE_RCS_STRING);"
+ errorLine2=" ~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/data/ApnSetting.java"
+ line="509"
+ column="30"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `MTU_V4` is a flagged API and should be inside an `if (Flags.apnSettingFieldSupportFlag())` check (or annotate the surrounding method `makeApnSetting` with `@FlaggedApi(Flags.FLAG_APN_SETTING_FIELD_SUPPORT_FLAG) to transfer requirement to caller`)"
+ errorLine1=" int mtuV4 = cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.MTU_V4));"
+ errorLine2=" ~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/data/ApnSetting.java"
+ line="1075"
+ column="83"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `setAlwaysOn()` is a flagged API and should be inside an `if (Flags.apnSettingFieldSupportFlag())` check (or annotate the surrounding method `makeApnSetting` with `@FlaggedApi(Flags.FLAG_APN_SETTING_FIELD_SUPPORT_FLAG) to transfer requirement to caller`)"
+ errorLine1=" return new Builder()"
+ errorLine2=" ^">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/data/ApnSetting.java"
+ line="1080"
+ column="16"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `MTU_V6` is a flagged API and should be inside an `if (Flags.apnSettingFieldSupportFlag())` check (or annotate the surrounding method `makeApnSetting` with `@FlaggedApi(Flags.FLAG_APN_SETTING_FIELD_SUPPORT_FLAG) to transfer requirement to caller`)"
+ errorLine1=" .setMtuV6(cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.MTU_V6)))"
+ errorLine2=" ~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/data/ApnSetting.java"
+ line="1126"
+ column="89"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `ALWAYS_ON` is a flagged API and should be inside an `if (Flags.apnSettingFieldSupportFlag())` check (or annotate the surrounding method `makeApnSetting` with `@FlaggedApi(Flags.FLAG_APN_SETTING_FIELD_SUPPORT_FLAG) to transfer requirement to caller`)"
+ errorLine1=" .setAlwaysOn(cursor.getInt(cursor.getColumnIndexOrThrow(Carriers.ALWAYS_ON)) == 1)"
+ errorLine2=" ~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/data/ApnSetting.java"
+ line="1137"
+ column="82"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `setAlwaysOn()` is a flagged API and should be inside an `if (Flags.apnSettingFieldSupportFlag())` check (or annotate the surrounding method `makeApnSetting` with `@FlaggedApi(Flags.FLAG_APN_SETTING_FIELD_SUPPORT_FLAG) to transfer requirement to caller`)"
+ errorLine1=" return new Builder()"
+ errorLine2=" ^">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/data/ApnSetting.java"
+ line="1151"
+ column="16"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `MTU_V4` is a flagged API and should be inside an `if (Flags.apnSettingFieldSupportFlag())` check (or annotate the surrounding method `toContentValues` with `@FlaggedApi(Flags.FLAG_APN_SETTING_FIELD_SUPPORT_FLAG) to transfer requirement to caller`)"
+ errorLine1=" apnValue.put(Telephony.Carriers.MTU_V4, mMtuV4);"
+ errorLine2=" ~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/data/ApnSetting.java"
+ line="1500"
+ column="41"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `MTU_V6` is a flagged API and should be inside an `if (Flags.apnSettingFieldSupportFlag())` check (or annotate the surrounding method `toContentValues` with `@FlaggedApi(Flags.FLAG_APN_SETTING_FIELD_SUPPORT_FLAG) to transfer requirement to caller`)"
+ errorLine1=" apnValue.put(Telephony.Carriers.MTU_V6, mMtuV6);"
+ errorLine2=" ~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/data/ApnSetting.java"
+ line="1501"
+ column="41"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `ALWAYS_ON` is a flagged API and should be inside an `if (Flags.apnSettingFieldSupportFlag())` check (or annotate the surrounding method `toContentValues` with `@FlaggedApi(Flags.FLAG_APN_SETTING_FIELD_SUPPORT_FLAG) to transfer requirement to caller`)"
+ errorLine1=" apnValue.put(Telephony.Carriers.ALWAYS_ON, mAlwaysOn);"
+ errorLine2=" ~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/data/ApnSetting.java"
+ line="1504"
+ column="41"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `setAlwaysOn()` is a flagged API and should be inside an `if (Flags.apnSettingFieldSupportFlag())` check (or annotate the surrounding method `readFromParcel` with `@FlaggedApi(Flags.FLAG_APN_SETTING_FIELD_SUPPORT_FLAG) to transfer requirement to caller`)"
+ errorLine1=" return new Builder()"
+ errorLine2=" ^">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/data/ApnSetting.java"
+ line="1785"
+ column="16"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `TYPE_RCS` is a flagged API and should be inside an `if (Flags.carrierEnabledSatelliteFlag())` check (or annotate the surrounding method `build` with `@FlaggedApi(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG) to transfer requirement to caller`)"
+ errorLine1=" | TYPE_XCAP | TYPE_VSIM | TYPE_BIP | TYPE_ENTERPRISE | TYPE_RCS)) == 0"
+ errorLine2=" ~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/data/ApnSetting.java"
+ line="2386"
+ column="76"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `OPSTR_ACCESS_RESTRICTED_SETTINGS` is a flagged API and should be inside an `if (Flags.enhancedConfirmationModeApisEnabled())` check (or annotate the surrounding method `?` with `@FlaggedApi(Flags.FLAG_ENHANCED_CONFIRMATION_MODE_APIS_ENABLED) to transfer requirement to caller`)"
+ errorLine1=" new AppOpInfo.Builder(OP_ACCESS_RESTRICTED_SETTINGS, OPSTR_ACCESS_RESTRICTED_SETTINGS,"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/app/AppOpsManager.java"
+ line="2983"
+ column="62"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `OPSTR_CREATE_ACCESSIBILITY_OVERLAY` is a flagged API and should be inside an `if (Flags.createAccessibilityOverlayAppOpEnabled())` check (or annotate the surrounding method `?` with `@FlaggedApi(Flags.FLAG_CREATE_ACCESSIBILITY_OVERLAY_APP_OP_ENABLED) to transfer requirement to caller`)"
+ errorLine1=" OPSTR_CREATE_ACCESSIBILITY_OVERLAY,"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/app/AppOpsManager.java"
+ line="3050"
+ column="17"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `OPSTR_MEDIA_ROUTING_CONTROL` is a flagged API and should be inside an `if (Flags.enablePrivilegedRoutingForMediaRoutingControl())` check (or annotate the surrounding method `?` with `@FlaggedApi(Flags.FLAG_ENABLE_PRIVILEGED_ROUTING_FOR_MEDIA_ROUTING_CONTROL) to transfer requirement to caller`)"
+ errorLine1=" new AppOpInfo.Builder(OP_MEDIA_ROUTING_CONTROL, OPSTR_MEDIA_ROUTING_CONTROL,"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/app/AppOpsManager.java"
+ line="3053"
+ column="57"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `OPSTR_ENABLE_MOBILE_DATA_BY_USER` is a flagged API and should be inside an `if (Flags.opEnableMobileDataByUser())` check (or annotate the surrounding method `?` with `@FlaggedApi(Flags.FLAG_OP_ENABLE_MOBILE_DATA_BY_USER) to transfer requirement to caller`)"
+ errorLine1=" new AppOpInfo.Builder(OP_ENABLE_MOBILE_DATA_BY_USER, OPSTR_ENABLE_MOBILE_DATA_BY_USER,"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/app/AppOpsManager.java"
+ line="3056"
+ column="62"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `OPSTR_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER` is a flagged API and should be inside an `if (Flags.rapidClearNotificationsByListenerAppOpEnabled())` check (or annotate the surrounding method `?` with `@FlaggedApi(Flags.FLAG_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER_APP_OP_ENABLED) to transfer requirement to caller`)"
+ errorLine1=" OPSTR_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER,"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/app/AppOpsManager.java"
+ line="3061"
+ column="17"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `OPSTR_EMERGENCY_LOCATION` is a flagged API and should be inside an `if (Flags.locationBypass())` check (or annotate the surrounding method `?` with `@FlaggedApi(Flags.FLAG_LOCATION_BYPASS) to transfer requirement to caller`)"
+ errorLine1=" new AppOpInfo.Builder(OP_EMERGENCY_LOCATION, OPSTR_EMERGENCY_LOCATION, "EMERGENCY_LOCATION")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/app/AppOpsManager.java"
+ line="3077"
+ column="54"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `OPSTR_RECEIVE_SENSITIVE_NOTIFICATIONS` is a flagged API and should be inside an `if (Flags.redactSensitiveNotificationsFromUntrustedListeners())` check (or annotate the surrounding method `?` with `@FlaggedApi(Flags.FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS) to transfer requirement to caller`)"
+ errorLine1=" OPSTR_RECEIVE_SENSITIVE_NOTIFICATIONS, "RECEIVE_SENSITIVE_NOTIFICATIONS")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/app/AppOpsManager.java"
+ line="3083"
+ column="17"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `PERSISTENT_DEVICE_ID_DEFAULT` is a flagged API and should be inside an `if (Flags.persistentDeviceIdApi())` check (or annotate the surrounding method `OpEventProxyInfo` with `@FlaggedApi(Flags.FLAG_PERSISTENT_DEVICE_ID_API) to transfer requirement to caller`)"
+ errorLine1=" VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/app/AppOpsManager.java"
+ line="3550"
+ column="42"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `PERSISTENT_DEVICE_ID_DEFAULT` is a flagged API and should be inside an `if (Flags.persistentDeviceIdApi())` check (or annotate the surrounding method `onOpChanged` with `@FlaggedApi(Flags.FLAG_PERSISTENT_DEVICE_ID_API) to transfer requirement to caller`)"
+ errorLine1=" VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT)) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/app/AppOpsManager.java"
+ line="7483"
+ column="42"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `PERSISTENT_DEVICE_ID_DEFAULT` is a flagged API and should be inside an `if (Flags.persistentDeviceIdApi())` check (or annotate the surrounding method `getPackagesForOps` with `@FlaggedApi(Flags.FLAG_PERSISTENT_DEVICE_ID_API) to transfer requirement to caller`)"
+ errorLine1=" VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/app/AppOpsManager.java"
+ line="7891"
+ column="42"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `getDeviceId()` is a flagged API and should be inside an `if (Flags.deviceAwarePermissionApisEnabled())` check (or annotate the surrounding method `unsafeCheckOpRawNoThrow` with `@FlaggedApi(Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED) to transfer requirement to caller`)"
+ errorLine1=" attributionSource.getPackageName(), attributionSource.getDeviceId());"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/app/AppOpsManager.java"
+ line="8848"
+ column="53"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `getDeviceId()` is a flagged API and should be inside an `if (Flags.deviceAwarePermissionApisEnabled())` check (or annotate the surrounding method `noteOpNoThrow` with `@FlaggedApi(Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED) to transfer requirement to caller`)"
+ errorLine1=" attributionSource.getAttributionTag(), attributionSource.getDeviceId(), message);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/app/AppOpsManager.java"
+ line="9034"
+ column="56"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `getDeviceId()` is a flagged API and should be inside an `if (Flags.deviceAwarePermissionApisEnabled())` check (or annotate the surrounding method `checkOpNoThrow` with `@FlaggedApi(Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED) to transfer requirement to caller`)"
+ errorLine1=" attributionSource.getDeviceId());"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/app/AppOpsManager.java"
+ line="9329"
+ column="17"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `getDeviceId()` is a flagged API and should be inside an `if (Flags.deviceAwarePermissionApisEnabled())` check (or annotate the surrounding method `startOpNoThrow` with `@FlaggedApi(Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED) to transfer requirement to caller`)"
+ errorLine1=" attributionSource.getAttributionTag(), attributionSource.getDeviceId(),"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/app/AppOpsManager.java"
+ line="9589"
+ column="56"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `getDeviceId()` is a flagged API and should be inside an `if (Flags.deviceAwarePermissionApisEnabled())` check (or annotate the surrounding method `finishOp` with `@FlaggedApi(Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED) to transfer requirement to caller`)"
+ errorLine1=" attributionSource.getDeviceId());"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/app/AppOpsManager.java"
+ line="9842"
+ column="17"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `EXTRA_REQUEST_PERMISSIONS_DEVICE_ID` is a flagged API and should be inside an `if (Flags.deviceAwarePermissionApisEnabled())` check (or annotate the surrounding method `buildRequestPermissionsIntent` with `@FlaggedApi(Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED) to transfer requirement to caller`)"
+ errorLine1=" intent.putExtra(EXTRA_REQUEST_PERMISSIONS_DEVICE_ID, mContext.getDeviceId());"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/app/ApplicationPackageManager.java"
+ line="965"
+ column="25"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `APP_METADATA_SOURCE_UNKNOWN` is a flagged API and should be inside an `if (Flags.aslInApkAppMetadataSource())` check (or annotate the surrounding method `getAppMetadataSource` with `@FlaggedApi(Flags.FLAG_ASL_IN_APK_APP_METADATA_SOURCE) to transfer requirement to caller`)"
+ errorLine1=" int source = PackageManager.APP_METADATA_SOURCE_UNKNOWN;"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/app/ApplicationPackageManager.java"
+ line="1283"
+ column="37"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `isArchived` is a flagged API and should be inside an `if (Flags.archiving())` check (or annotate the surrounding method `loadUnbadgedItemIcon` with `@FlaggedApi(Flags.FLAG_ARCHIVING) to transfer requirement to caller`)"
+ errorLine1=" if (itemInfo.isArchived) {"
+ errorLine2=" ~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/app/ApplicationPackageManager.java"
+ line="3430"
+ column="26"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `ArchivedPackageInfo()` is a flagged API and should be inside an `if (Flags.archiving())` check (or annotate the surrounding method `getArchivedPackage` with `@FlaggedApi(Flags.FLAG_ARCHIVING) to transfer requirement to caller`)"
+ errorLine1=" return new ArchivedPackageInfo(parcel);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/app/ApplicationPackageManager.java"
+ line="3995"
+ column="20"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `getPendingCredentialRequest()` is a flagged API and should be inside an `if (Flags.autofillCredmanDevIntegration())` check (or annotate the surrounding method `dump` with `@FlaggedApi(Flags.FLAG_AUTOFILL_CREDMAN_DEV_INTEGRATION) to transfer requirement to caller`)"
+ errorLine1=" GetCredentialRequest getCredentialRequest = node.getPendingCredentialRequest();"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/app/assist/AssistStructure.java"
+ line="2657"
+ column="53"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `AttributionSource()` is a flagged API and should be inside an `if (Flags.deviceAwarePermissionApisEnabled())` check (or annotate the surrounding method `AttributionSource` with `@FlaggedApi(Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED) to transfer requirement to caller`)"
+ errorLine1=" this(uid, Process.INVALID_PID, packageName, attributionTag, sDefaultToken, null,"
+ errorLine2=" ^">
+ <location
+ file="frameworks/base/core/java/android/content/AttributionSource.java"
+ line="112"
+ column="9"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `AttributionSource()` is a flagged API and should be inside an `if (Flags.deviceAwarePermissionApisEnabled())` check (or annotate the surrounding method `AttributionSource` with `@FlaggedApi(Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED) to transfer requirement to caller`)"
+ errorLine1=" this(uid, Process.INVALID_PID, packageName, attributionTag, token,"
+ errorLine2=" ^">
+ <location
+ file="frameworks/base/core/java/android/content/AttributionSource.java"
+ line="126"
+ column="9"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `AttributionSource()` is a flagged API and should be inside an `if (Flags.deviceAwarePermissionApisEnabled())` check (or annotate the surrounding method `AttributionSource` with `@FlaggedApi(Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED) to transfer requirement to caller`)"
+ errorLine1=" this(uid, pid, packageName, attributionTag, token, /*renouncedPermissions*/ null,"
+ errorLine2=" ^">
+ <location
+ file="frameworks/base/core/java/android/content/AttributionSource.java"
+ line="133"
+ column="9"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `AttributionSource()` is a flagged API and should be inside an `if (Flags.deviceAwarePermissionApisEnabled())` check (or annotate the surrounding method `AttributionSource` with `@FlaggedApi(Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED) to transfer requirement to caller`)"
+ errorLine1=" this(uid, Process.INVALID_PID, packageName, attributionTag, sDefaultToken,"
+ errorLine2=" ^">
+ <location
+ file="frameworks/base/core/java/android/content/AttributionSource.java"
+ line="142"
+ column="9"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `AttributionSource()` is a flagged API and should be inside an `if (Flags.deviceAwarePermissionApisEnabled())` check (or annotate the surrounding method `AttributionSource` with `@FlaggedApi(Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED) to transfer requirement to caller`)"
+ errorLine1=" this(current.getUid(), current.getPid(), current.getPackageName(),"
+ errorLine2=" ^">
+ <location
+ file="frameworks/base/core/java/android/content/AttributionSource.java"
+ line="150"
+ column="9"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `getDeviceId()` is a flagged API and should be inside an `if (Flags.deviceAwarePermissionApisEnabled())` check (or annotate the surrounding method `AttributionSource` with `@FlaggedApi(Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED) to transfer requirement to caller`)"
+ errorLine1=" current.mAttributionSourceState.renouncedPermissions, current.getDeviceId(), next);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/content/AttributionSource.java"
+ line="152"
+ column="71"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `AttributionSource()` is a flagged API and should be inside an `if (Flags.deviceAwarePermissionApisEnabled())` check (or annotate the surrounding method `AttributionSource` with `@FlaggedApi(Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED) to transfer requirement to caller`)"
+ errorLine1=" this(uid, pid, packageName, attributionTag, sDefaultToken, renouncedPermissions, deviceId,"
+ errorLine2=" ^">
+ <location
+ file="frameworks/base/core/java/android/content/AttributionSource.java"
+ line="159"
+ column="9"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `AttributionSource()` is a flagged API and should be inside an `if (Flags.deviceAwarePermissionApisEnabled())` check (or annotate the surrounding method `withNextAttributionSource` with `@FlaggedApi(Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED) to transfer requirement to caller`)"
+ errorLine1=" return new AttributionSource(getUid(), getPid(), getPackageName(), getAttributionTag(),"
+ errorLine2=" ^">
+ <location
+ file="frameworks/base/core/java/android/content/AttributionSource.java"
+ line="212"
+ column="16"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `getDeviceId()` is a flagged API and should be inside an `if (Flags.deviceAwarePermissionApisEnabled())` check (or annotate the surrounding method `withNextAttributionSource` with `@FlaggedApi(Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED) to transfer requirement to caller`)"
+ errorLine1=" getToken(), mAttributionSourceState.renouncedPermissions, getDeviceId(), next);"
+ errorLine2=" ~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/content/AttributionSource.java"
+ line="213"
+ column="75"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `AttributionSource()` is a flagged API and should be inside an `if (Flags.deviceAwarePermissionApisEnabled())` check (or annotate the surrounding method `withPackageName` with `@FlaggedApi(Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED) to transfer requirement to caller`)"
+ errorLine1=" return new AttributionSource(getUid(), getPid(), packageName, getAttributionTag(),"
+ errorLine2=" ^">
+ <location
+ file="frameworks/base/core/java/android/content/AttributionSource.java"
+ line="218"
+ column="16"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `getDeviceId()` is a flagged API and should be inside an `if (Flags.deviceAwarePermissionApisEnabled())` check (or annotate the surrounding method `withPackageName` with `@FlaggedApi(Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED) to transfer requirement to caller`)"
+ errorLine1=" getToken(), mAttributionSourceState.renouncedPermissions, getDeviceId(), getNext());"
+ errorLine2=" ~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/content/AttributionSource.java"
+ line="219"
+ column="74"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `AttributionSource()` is a flagged API and should be inside an `if (Flags.deviceAwarePermissionApisEnabled())` check (or annotate the surrounding method `withToken` with `@FlaggedApi(Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED) to transfer requirement to caller`)"
+ errorLine1=" return new AttributionSource(getUid(), getPid(), getPackageName(), getAttributionTag(),"
+ errorLine2=" ^">
+ <location
+ file="frameworks/base/core/java/android/content/AttributionSource.java"
+ line="224"
+ column="16"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `getDeviceId()` is a flagged API and should be inside an `if (Flags.deviceAwarePermissionApisEnabled())` check (or annotate the surrounding method `withToken` with `@FlaggedApi(Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED) to transfer requirement to caller`)"
+ errorLine1=" token, mAttributionSourceState.renouncedPermissions, getDeviceId(), getNext());"
+ errorLine2=" ~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/content/AttributionSource.java"
+ line="225"
+ column="70"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `AttributionSource()` is a flagged API and should be inside an `if (Flags.deviceAwarePermissionApisEnabled())` check (or annotate the surrounding method `withPid` with `@FlaggedApi(Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED) to transfer requirement to caller`)"
+ errorLine1=" return new AttributionSource(getUid(), pid, getPackageName(), getAttributionTag(),"
+ errorLine2=" ^">
+ <location
+ file="frameworks/base/core/java/android/content/AttributionSource.java"
+ line="235"
+ column="16"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `getDeviceId()` is a flagged API and should be inside an `if (Flags.deviceAwarePermissionApisEnabled())` check (or annotate the surrounding method `withPid` with `@FlaggedApi(Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED) to transfer requirement to caller`)"
+ errorLine1=" getToken(), mAttributionSourceState.renouncedPermissions, getDeviceId(), getNext());"
+ errorLine2=" ~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/content/AttributionSource.java"
+ line="236"
+ column="75"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `AttributionSource()` is a flagged API and should be inside an `if (Flags.deviceAwarePermissionApisEnabled())` check (or annotate the surrounding method `withDeviceId` with `@FlaggedApi(Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED) to transfer requirement to caller`)"
+ errorLine1=" return new AttributionSource(getUid(), getPid(), getPackageName(), getAttributionTag(),"
+ errorLine2=" ^">
+ <location
+ file="frameworks/base/core/java/android/content/AttributionSource.java"
+ line="241"
+ column="16"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `setDeviceId()` is a flagged API and should be inside an `if (Flags.deviceAwarePermissionApisEnabled())` check (or annotate the surrounding method `myAttributionSource` with `@FlaggedApi(Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED) to transfer requirement to caller`)"
+ errorLine1=" return new AttributionSource.Builder(uid)"
+ errorLine2=" ^">
+ <location
+ file="frameworks/base/core/java/android/content/AttributionSource.java"
+ line="284"
+ column="20"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `isRegisteredAttributionSource()` is a flagged API and should be inside an `if (Flags.shouldRegisterAttributionSource())` check (or annotate the surrounding method `isTrusted` with `@FlaggedApi(Flags.FLAG_SHOULD_REGISTER_ATTRIBUTION_SOURCE) to transfer requirement to caller`)"
+ errorLine1=" && context.getSystemService(PermissionManager.class)"
+ errorLine2=" ^">
+ <location
+ file="frameworks/base/core/java/android/content/AttributionSource.java"
+ line="487"
+ column="20"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `isResumed()` is a flagged API and should be inside an `if (Flags.enableNfcMainline())` check (or annotate the surrounding method `isDisablingEnterExitEventForAutofill` with `@FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE) to transfer requirement to caller`)"
+ errorLine1=" return mAutoFillIgnoreFirstResumePause || !mActivity.isResumed();"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/view/autofill/AutofillClientController.java"
+ line="473"
+ column="52"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `FIELD_NAME` is a flagged API and should be inside an `if (Flags.modesApi())` check (or annotate the surrounding method `fieldsToString` with `@FlaggedApi(Flags.FLAG_MODES_API) to transfer requirement to caller`)"
+ errorLine1=" if ((bitmask & FIELD_NAME) != 0) {"
+ errorLine2=" ~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/app/AutomaticZenRule.java"
+ line="582"
+ column="24"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `FIELD_INTERRUPTION_FILTER` is a flagged API and should be inside an `if (Flags.modesApi())` check (or annotate the surrounding method `fieldsToString` with `@FlaggedApi(Flags.FLAG_MODES_API) to transfer requirement to caller`)"
+ errorLine1=" if ((bitmask & FIELD_INTERRUPTION_FILTER) != 0) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/app/AutomaticZenRule.java"
+ line="585"
+ column="24"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `FIELD_ICON` is a flagged API and should be inside an `if (Flags.modesApi())` check (or annotate the surrounding method `fieldsToString` with `@FlaggedApi(Flags.FLAG_MODES_API) to transfer requirement to caller`)"
+ errorLine1=" if ((bitmask & FIELD_ICON) != 0) {"
+ errorLine2=" ~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/app/AutomaticZenRule.java"
+ line="588"
+ column="24"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `getFrameTimeNanos()` is a flagged API and should be inside an `if (Flags.expectedPresentationTimeApi())` check (or annotate the surrounding method `run` with `@FlaggedApi(Flags.FLAG_EXPECTED_PRESENTATION_TIME_API) to transfer requirement to caller`)"
+ errorLine1=" doConsumeBatchedInput(mChoreographer.getFrameTimeNanos());"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/view/BatchedInputEventReceiver.java"
+ line="130"
+ column="39"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `Gainmap()` is a flagged API and should be inside an `if (Flags.gainmapConstructorWithMetadata())` check (or annotate the surrounding method `createBitmap` with `@FlaggedApi(Flags.FLAG_GAINMAP_CONSTRUCTOR_WITH_METADATA) to transfer requirement to caller`)"
+ errorLine1=" bitmap.setGainmap(new Gainmap(source.getGainmap(), newMapContents));"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/graphics/java/android/graphics/Bitmap.java"
+ line="1030"
+ column="35"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `Gainmap()` is a flagged API and should be inside an `if (Flags.gainmapConstructorWithMetadata())` check (or annotate the surrounding method `setOverrideGainmap` with `@FlaggedApi(Flags.FLAG_GAINMAP_CONSTRUCTOR_WITH_METADATA) to transfer requirement to caller`)"
+ errorLine1=" mOverrideGainmap = new Gainmap(overrideGainmap, overrideGainmap.getGainmapContents());"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/graphics/java/android/graphics/BitmapShader.java"
+ line="193"
+ column="32"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `set()` is a flagged API and should be inside an `if (Flags.fixLineHeightForLocale())` check (or annotate the surrounding method `isBoring` with `@FlaggedApi(Flags.FLAG_FIX_LINE_HEIGHT_FOR_LOCALE) to transfer requirement to caller`)"
+ errorLine1=" fm.set(minimumFontMetrics);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/text/BoringLayout.java"
+ line="594"
+ column="17"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `getUseBoundsForWidth()` is a flagged API and should be inside an `if (Flags.useBoundsForWidth())` check (or annotate the surrounding method `getLineMax` with `@FlaggedApi(Flags.FLAG_USE_BOUNDS_FOR_WIDTH) to transfer requirement to caller`)"
+ errorLine1=" if (getUseBoundsForWidth()) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/text/BoringLayout.java"
+ line="658"
+ column="13"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `getUseBoundsForWidth()` is a flagged API and should be inside an `if (Flags.useBoundsForWidth())` check (or annotate the surrounding method `getLineWidth` with `@FlaggedApi(Flags.FLAG_USE_BOUNDS_FOR_WIDTH) to transfer requirement to caller`)"
+ errorLine1=" if (getUseBoundsForWidth()) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/text/BoringLayout.java"
+ line="667"
+ column="13"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `getShiftDrawingOffsetForStartOverhang()` is a flagged API and should be inside an `if (Flags.useBoundsForWidth())` check (or annotate the surrounding method `draw` with `@FlaggedApi(Flags.FLAG_USE_BOUNDS_FOR_WIDTH) to transfer requirement to caller`)"
+ errorLine1=" if (getUseBoundsForWidth() && getShiftDrawingOffsetForStartOverhang()) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/text/BoringLayout.java"
+ line="720"
+ column="43"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `getUseBoundsForWidth()` is a flagged API and should be inside an `if (Flags.useBoundsForWidth())` check (or annotate the surrounding method `draw` with `@FlaggedApi(Flags.FLAG_USE_BOUNDS_FOR_WIDTH) to transfer requirement to caller`)"
+ errorLine1=" if (getUseBoundsForWidth() && getShiftDrawingOffsetForStartOverhang()) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/text/BoringLayout.java"
+ line="720"
+ column="17"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `createFromParcelBody()` is a flagged API and should be inside an `if (Flags.tiafVApis())` check (or annotate the surrounding method `createFromParcel` with `@FlaggedApi(Flags.FLAG_TIAF_V_APIS) to transfer requirement to caller`)"
+ errorLine1=" return SignalingDataRequest.createFromParcelBody(source);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/media/java/android/media/tv/BroadcastInfoRequest.java"
+ line="89"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `createFromParcelBody()` is a flagged API and should be inside an `if (Flags.tiafVApis())` check (or annotate the surrounding method `createFromParcel` with `@FlaggedApi(Flags.FLAG_TIAF_V_APIS) to transfer requirement to caller`)"
+ errorLine1=" return SignalingDataResponse.createFromParcelBody(source);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/media/java/android/media/tv/BroadcastInfoResponse.java"
+ line="75"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `BUGREPORT_MODE_ONBOARDING` is a flagged API and should be inside an `if (Flags.onboardingBugreportV2Enabled())` check (or annotate the surrounding method `?` with `@FlaggedApi(Flags.FLAG_ONBOARDING_BUGREPORT_V2_ENABLED) to transfer requirement to caller`)"
+ errorLine1=" public static final int BUGREPORT_MODE_MAX_VALUE = BUGREPORT_MODE_ONBOARDING;"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/os/BugreportParams.java"
+ line="139"
+ column="56"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `PROPERTY_IS_TRANSACTIONAL` is a flagged API and should be inside an `if (Flags.voipAppActionsSupport())` check (or annotate the surrounding method `propertiesToString` with `@FlaggedApi(Flags.FLAG_VOIP_APP_ACTIONS_SUPPORT) to transfer requirement to caller`)"
+ errorLine1=" if (hasProperty(properties, PROPERTY_IS_TRANSACTIONAL)) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telecomm/java/android/telecom/Call.java"
+ line="854"
+ column="41"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `getImsReasonInfo()` is a flagged API and should be inside an `if (Flags.telecomResolveHiddenDependencies())` check (or annotate the surrounding method `handleCallDisconnected` with `@FlaggedApi(Flags.FLAG_TELECOM_RESOLVE_HIDDEN_DEPENDENCIES) to transfer requirement to caller`)"
+ errorLine1=" if (disconnectCause.getImsReasonInfo() != null) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telecomm/java/android/telecom/CallDiagnosticService.java"
+ line="365"
+ column="13"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `getImsReasonInfo()` is a flagged API and should be inside an `if (Flags.telecomResolveHiddenDependencies())` check (or annotate the surrounding method `handleCallDisconnected` with `@FlaggedApi(Flags.FLAG_TELECOM_RESOLVE_HIDDEN_DEPENDENCIES) to transfer requirement to caller`)"
+ errorLine1=" message = callDiagnostics.onCallDisconnected(disconnectCause.getImsReasonInfo());"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telecomm/java/android/telecom/CallDiagnosticService.java"
+ line="366"
+ column="58"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `getTelephonyDisconnectCause()` is a flagged API and should be inside an `if (Flags.telecomResolveHiddenDependencies())` check (or annotate the surrounding method `handleCallDisconnected` with `@FlaggedApi(Flags.FLAG_TELECOM_RESOLVE_HIDDEN_DEPENDENCIES) to transfer requirement to caller`)"
+ errorLine1=" disconnectCause.getTelephonyDisconnectCause(),"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telecomm/java/android/telecom/CallDiagnosticService.java"
+ line="369"
+ column="21"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `getTelephonyPreciseDisconnectCause()` is a flagged API and should be inside an `if (Flags.telecomResolveHiddenDependencies())` check (or annotate the surrounding method `handleCallDisconnected` with `@FlaggedApi(Flags.FLAG_TELECOM_RESOLVE_HIDDEN_DEPENDENCIES) to transfer requirement to caller`)"
+ errorLine1=" disconnectCause.getTelephonyPreciseDisconnectCause());"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telecomm/java/android/telecom/CallDiagnosticService.java"
+ line="370"
+ column="21"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `POLICY_TYPE_CAMERA` is a flagged API and should be inside an `if (Flags.virtualCamera())` check (or annotate the surrounding method `getDevicePolicyFromContext` with `@FlaggedApi(Flags.FLAG_VIRTUAL_CAMERA) to transfer requirement to caller`)"
+ errorLine1=" return virtualDeviceManager.getDevicePolicy(context.getDeviceId(), POLICY_TYPE_CAMERA);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/hardware/Camera.java"
+ line="350"
+ column="76"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `FALLBACK_PACKAGE_NAME` is a flagged API and should be inside an `if (Flags.concertMode())` check (or annotate the surrounding method `onSuccess` with `@FlaggedApi(Flags.FLAG_CONCERT_MODE) to transfer requirement to caller`)"
+ errorLine1=" .getString(FALLBACK_PACKAGE_NAME);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java"
+ line="591"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `POLICY_TYPE_CAMERA` is a flagged API and should be inside an `if (Flags.virtualCamera())` check (or annotate the surrounding method `getDevicePolicyFromContext` with `@FlaggedApi(Flags.FLAG_VIRTUAL_CAMERA) to transfer requirement to caller`)"
+ errorLine1=" return mVirtualDeviceManager.getDevicePolicy(context.getDeviceId(), POLICY_TYPE_CAMERA);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/hardware/camera2/CameraManager.java"
+ line="584"
+ column="77"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `CameraDeviceSetupImpl()` is a flagged API and should be inside an `if (Flags.cameraDeviceSetup())` check (or annotate the surrounding method `getCameraDeviceSetupUnsafe` with `@FlaggedApi(Flags.FLAG_CAMERA_DEVICE_SETUP) to transfer requirement to caller`)"
+ errorLine1=" return new CameraDeviceSetupImpl(cameraId, /*cameraManager=*/ this, mContext);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/hardware/camera2/CameraManager.java"
+ line="903"
+ column="16"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `isCameraDeviceSetupSupported()` is a flagged API and should be inside an `if (Flags.cameraDeviceSetup())` check (or annotate the surrounding method `openCameraDeviceUserAsync` with `@FlaggedApi(Flags.FLAG_CAMERA_DEVICE_SETUP) to transfer requirement to caller`)"
+ errorLine1=" && CameraDeviceSetupImpl.isCameraDeviceSetupSupported(characteristics)) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/hardware/camera2/CameraManager.java"
+ line="983"
+ column="24"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Class `DeviceStateManager` is a flagged API and should be inside an `if (Flags.deviceStatePropertyApi())` check (or annotate the surrounding method `registerDeviceStateListener` with `@FlaggedApi(Flags.FLAG_DEVICE_STATE_PROPERTY_API) to transfer requirement to caller`)"
+ errorLine1=" ctx.getSystemService(DeviceStateManager.class).registerCallback("
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/hardware/camera2/CameraManager.java"
+ line="2141"
+ column="46"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `registerCallback()` is a flagged API and should be inside an `if (Flags.deviceStatePropertyApi())` check (or annotate the surrounding method `registerDeviceStateListener` with `@FlaggedApi(Flags.FLAG_DEVICE_STATE_PROPERTY_API) to transfer requirement to caller`)"
+ errorLine1=" ctx.getSystemService(DeviceStateManager.class).registerCallback("
+ errorLine2=" ^">
+ <location
+ file="frameworks/base/core/java/android/hardware/camera2/CameraManager.java"
+ line="2141"
+ column="25"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `STATISTICS_LENS_INTRINSICS_SAMPLES` is a flagged API and should be inside an `if (Flags.concertMode())` check (or annotate the surrounding method `?` with `@FlaggedApi(Flags.FLAG_CONCERT_MODE) to transfer requirement to caller`)"
+ errorLine1=" CaptureResult.STATISTICS_LENS_INTRINSICS_SAMPLES.getNativeKey(),"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/hardware/camera2/impl/CameraMetadataNative.java"
+ line="856"
+ column="31"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `STATISTICS_LENS_INTRINSICS_SAMPLES` is a flagged API and should be inside an `if (Flags.concertMode())` check (or annotate the surrounding method `?` with `@FlaggedApi(Flags.FLAG_CONCERT_MODE) to transfer requirement to caller`)"
+ errorLine1=" CaptureResult.STATISTICS_LENS_INTRINSICS_SAMPLES.getNativeKey(),"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/hardware/camera2/impl/CameraMetadataNative.java"
+ line="2021"
+ column="31"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `KEY_EMERGENCY_OVER_IMS_SUPPORTED_3GPP_NETWORK_TYPES_INT_ARRAY` is a flagged API and should be inside an `if (Flags.useOemDomainSelectionService())` check (or annotate the surrounding method `getDefaults` with `@FlaggedApi(Flags.FLAG_USE_OEM_DOMAIN_SELECTION_SERVICE) to transfer requirement to caller`)"
+ errorLine1=" KEY_EMERGENCY_OVER_IMS_SUPPORTED_3GPP_NETWORK_TYPES_INT_ARRAY,"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/CarrierConfigManager.java"
+ line="8054"
+ column="21"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `KEY_EMERGENCY_OVER_IMS_ROAMING_SUPPORTED_3GPP_NETWORK_TYPES_INT_ARRAY` is a flagged API and should be inside an `if (Flags.useOemDomainSelectionService())` check (or annotate the surrounding method `getDefaults` with `@FlaggedApi(Flags.FLAG_USE_OEM_DOMAIN_SELECTION_SERVICE) to transfer requirement to caller`)"
+ errorLine1=" KEY_EMERGENCY_OVER_IMS_ROAMING_SUPPORTED_3GPP_NETWORK_TYPES_INT_ARRAY,"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/CarrierConfigManager.java"
+ line="8060"
+ column="21"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `KEY_EMERGENCY_OVER_CS_SUPPORTED_ACCESS_NETWORK_TYPES_INT_ARRAY` is a flagged API and should be inside an `if (Flags.useOemDomainSelectionService())` check (or annotate the surrounding method `getDefaults` with `@FlaggedApi(Flags.FLAG_USE_OEM_DOMAIN_SELECTION_SERVICE) to transfer requirement to caller`)"
+ errorLine1=" KEY_EMERGENCY_OVER_CS_SUPPORTED_ACCESS_NETWORK_TYPES_INT_ARRAY,"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/CarrierConfigManager.java"
+ line="8066"
+ column="21"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `KEY_EMERGENCY_OVER_CS_ROAMING_SUPPORTED_ACCESS_NETWORK_TYPES_INT_ARRAY` is a flagged API and should be inside an `if (Flags.useOemDomainSelectionService())` check (or annotate the surrounding method `getDefaults` with `@FlaggedApi(Flags.FLAG_USE_OEM_DOMAIN_SELECTION_SERVICE) to transfer requirement to caller`)"
+ errorLine1=" KEY_EMERGENCY_OVER_CS_ROAMING_SUPPORTED_ACCESS_NETWORK_TYPES_INT_ARRAY,"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/CarrierConfigManager.java"
+ line="8073"
+ column="21"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `KEY_EMERGENCY_DOMAIN_PREFERENCE_INT_ARRAY` is a flagged API and should be inside an `if (Flags.useOemDomainSelectionService())` check (or annotate the surrounding method `getDefaults` with `@FlaggedApi(Flags.FLAG_USE_OEM_DOMAIN_SELECTION_SERVICE) to transfer requirement to caller`)"
+ errorLine1=" defaults.putIntArray(KEY_EMERGENCY_DOMAIN_PREFERENCE_INT_ARRAY,"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/CarrierConfigManager.java"
+ line="8079"
+ column="34"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `DOMAIN_PS_3GPP` is a flagged API and should be inside an `if (Flags.useOemDomainSelectionService())` check (or annotate the surrounding method `getDefaults` with `@FlaggedApi(Flags.FLAG_USE_OEM_DOMAIN_SELECTION_SERVICE) to transfer requirement to caller`)"
+ errorLine1=" DOMAIN_PS_3GPP,"
+ errorLine2=" ~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/CarrierConfigManager.java"
+ line="8081"
+ column="25"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `DOMAIN_CS` is a flagged API and should be inside an `if (Flags.useOemDomainSelectionService())` check (or annotate the surrounding method `getDefaults` with `@FlaggedApi(Flags.FLAG_USE_OEM_DOMAIN_SELECTION_SERVICE) to transfer requirement to caller`)"
+ errorLine1=" DOMAIN_CS,"
+ errorLine2=" ~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/CarrierConfigManager.java"
+ line="8082"
+ column="25"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `DOMAIN_PS_NON_3GPP` is a flagged API and should be inside an `if (Flags.useOemDomainSelectionService())` check (or annotate the surrounding method `getDefaults` with `@FlaggedApi(Flags.FLAG_USE_OEM_DOMAIN_SELECTION_SERVICE) to transfer requirement to caller`)"
+ errorLine1=" DOMAIN_PS_NON_3GPP"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/CarrierConfigManager.java"
+ line="8083"
+ column="25"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `KEY_EMERGENCY_DOMAIN_PREFERENCE_ROAMING_INT_ARRAY` is a flagged API and should be inside an `if (Flags.useOemDomainSelectionService())` check (or annotate the surrounding method `getDefaults` with `@FlaggedApi(Flags.FLAG_USE_OEM_DOMAIN_SELECTION_SERVICE) to transfer requirement to caller`)"
+ errorLine1=" defaults.putIntArray(KEY_EMERGENCY_DOMAIN_PREFERENCE_ROAMING_INT_ARRAY,"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/CarrierConfigManager.java"
+ line="8085"
+ column="34"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `DOMAIN_PS_3GPP` is a flagged API and should be inside an `if (Flags.useOemDomainSelectionService())` check (or annotate the surrounding method `getDefaults` with `@FlaggedApi(Flags.FLAG_USE_OEM_DOMAIN_SELECTION_SERVICE) to transfer requirement to caller`)"
+ errorLine1=" DOMAIN_PS_3GPP,"
+ errorLine2=" ~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/CarrierConfigManager.java"
+ line="8087"
+ column="25"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `DOMAIN_CS` is a flagged API and should be inside an `if (Flags.useOemDomainSelectionService())` check (or annotate the surrounding method `getDefaults` with `@FlaggedApi(Flags.FLAG_USE_OEM_DOMAIN_SELECTION_SERVICE) to transfer requirement to caller`)"
+ errorLine1=" DOMAIN_CS,"
+ errorLine2=" ~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/CarrierConfigManager.java"
+ line="8088"
+ column="25"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `DOMAIN_PS_NON_3GPP` is a flagged API and should be inside an `if (Flags.useOemDomainSelectionService())` check (or annotate the surrounding method `getDefaults` with `@FlaggedApi(Flags.FLAG_USE_OEM_DOMAIN_SELECTION_SERVICE) to transfer requirement to caller`)"
+ errorLine1=" DOMAIN_PS_NON_3GPP"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/CarrierConfigManager.java"
+ line="8089"
+ column="25"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `KEY_PREFER_IMS_EMERGENCY_WHEN_VOICE_CALLS_ON_CS_BOOL` is a flagged API and should be inside an `if (Flags.useOemDomainSelectionService())` check (or annotate the surrounding method `getDefaults` with `@FlaggedApi(Flags.FLAG_USE_OEM_DOMAIN_SELECTION_SERVICE) to transfer requirement to caller`)"
+ errorLine1=" defaults.putBoolean(KEY_PREFER_IMS_EMERGENCY_WHEN_VOICE_CALLS_ON_CS_BOOL, false);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/CarrierConfigManager.java"
+ line="8092"
+ column="33"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `KEY_EMERGENCY_VOWIFI_REQUIRES_CONDITION_INT` is a flagged API and should be inside an `if (Flags.useOemDomainSelectionService())` check (or annotate the surrounding method `getDefaults` with `@FlaggedApi(Flags.FLAG_USE_OEM_DOMAIN_SELECTION_SERVICE) to transfer requirement to caller`)"
+ errorLine1=" defaults.putInt(KEY_EMERGENCY_VOWIFI_REQUIRES_CONDITION_INT, VOWIFI_REQUIRES_NONE);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/CarrierConfigManager.java"
+ line="8093"
+ column="29"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `VOWIFI_REQUIRES_NONE` is a flagged API and should be inside an `if (Flags.useOemDomainSelectionService())` check (or annotate the surrounding method `getDefaults` with `@FlaggedApi(Flags.FLAG_USE_OEM_DOMAIN_SELECTION_SERVICE) to transfer requirement to caller`)"
+ errorLine1=" defaults.putInt(KEY_EMERGENCY_VOWIFI_REQUIRES_CONDITION_INT, VOWIFI_REQUIRES_NONE);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/CarrierConfigManager.java"
+ line="8093"
+ column="74"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `KEY_MAXIMUM_NUMBER_OF_EMERGENCY_TRIES_OVER_VOWIFI_INT` is a flagged API and should be inside an `if (Flags.useOemDomainSelectionService())` check (or annotate the surrounding method `getDefaults` with `@FlaggedApi(Flags.FLAG_USE_OEM_DOMAIN_SELECTION_SERVICE) to transfer requirement to caller`)"
+ errorLine1=" defaults.putInt(KEY_MAXIMUM_NUMBER_OF_EMERGENCY_TRIES_OVER_VOWIFI_INT, 1);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/CarrierConfigManager.java"
+ line="8094"
+ column="29"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `KEY_EMERGENCY_SCAN_TIMER_SEC_INT` is a flagged API and should be inside an `if (Flags.useOemDomainSelectionService())` check (or annotate the surrounding method `getDefaults` with `@FlaggedApi(Flags.FLAG_USE_OEM_DOMAIN_SELECTION_SERVICE) to transfer requirement to caller`)"
+ errorLine1=" defaults.putInt(KEY_EMERGENCY_SCAN_TIMER_SEC_INT, 10);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/CarrierConfigManager.java"
+ line="8095"
+ column="29"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `KEY_MAXIMUM_CELLULAR_SEARCH_TIMER_SEC_INT` is a flagged API and should be inside an `if (Flags.useOemDomainSelectionService())` check (or annotate the surrounding method `getDefaults` with `@FlaggedApi(Flags.FLAG_USE_OEM_DOMAIN_SELECTION_SERVICE) to transfer requirement to caller`)"
+ errorLine1=" defaults.putInt(KEY_MAXIMUM_CELLULAR_SEARCH_TIMER_SEC_INT, REDIAL_TIMER_DISABLED);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/CarrierConfigManager.java"
+ line="8096"
+ column="29"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `REDIAL_TIMER_DISABLED` is a flagged API and should be inside an `if (Flags.useOemDomainSelectionService())` check (or annotate the surrounding method `getDefaults` with `@FlaggedApi(Flags.FLAG_USE_OEM_DOMAIN_SELECTION_SERVICE) to transfer requirement to caller`)"
+ errorLine1=" defaults.putInt(KEY_MAXIMUM_CELLULAR_SEARCH_TIMER_SEC_INT, REDIAL_TIMER_DISABLED);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/CarrierConfigManager.java"
+ line="8096"
+ column="72"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `KEY_EMERGENCY_NETWORK_SCAN_TYPE_INT` is a flagged API and should be inside an `if (Flags.useOemDomainSelectionService())` check (or annotate the surrounding method `getDefaults` with `@FlaggedApi(Flags.FLAG_USE_OEM_DOMAIN_SELECTION_SERVICE) to transfer requirement to caller`)"
+ errorLine1=" defaults.putInt(KEY_EMERGENCY_NETWORK_SCAN_TYPE_INT, SCAN_TYPE_NO_PREFERENCE);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/CarrierConfigManager.java"
+ line="8097"
+ column="29"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `SCAN_TYPE_NO_PREFERENCE` is a flagged API and should be inside an `if (Flags.useOemDomainSelectionService())` check (or annotate the surrounding method `getDefaults` with `@FlaggedApi(Flags.FLAG_USE_OEM_DOMAIN_SELECTION_SERVICE) to transfer requirement to caller`)"
+ errorLine1=" defaults.putInt(KEY_EMERGENCY_NETWORK_SCAN_TYPE_INT, SCAN_TYPE_NO_PREFERENCE);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/CarrierConfigManager.java"
+ line="8097"
+ column="66"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `KEY_EMERGENCY_CALL_SETUP_TIMER_ON_CURRENT_NETWORK_SEC_INT` is a flagged API and should be inside an `if (Flags.useOemDomainSelectionService())` check (or annotate the surrounding method `getDefaults` with `@FlaggedApi(Flags.FLAG_USE_OEM_DOMAIN_SELECTION_SERVICE) to transfer requirement to caller`)"
+ errorLine1=" defaults.putInt(KEY_EMERGENCY_CALL_SETUP_TIMER_ON_CURRENT_NETWORK_SEC_INT, 0);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/CarrierConfigManager.java"
+ line="8098"
+ column="29"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `KEY_EMERGENCY_REQUIRES_IMS_REGISTRATION_BOOL` is a flagged API and should be inside an `if (Flags.useOemDomainSelectionService())` check (or annotate the surrounding method `getDefaults` with `@FlaggedApi(Flags.FLAG_USE_OEM_DOMAIN_SELECTION_SERVICE) to transfer requirement to caller`)"
+ errorLine1=" defaults.putBoolean(KEY_EMERGENCY_REQUIRES_IMS_REGISTRATION_BOOL, false);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/CarrierConfigManager.java"
+ line="8099"
+ column="33"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `KEY_EMERGENCY_LTE_PREFERRED_AFTER_NR_FAILED_BOOL` is a flagged API and should be inside an `if (Flags.useOemDomainSelectionService())` check (or annotate the surrounding method `getDefaults` with `@FlaggedApi(Flags.FLAG_USE_OEM_DOMAIN_SELECTION_SERVICE) to transfer requirement to caller`)"
+ errorLine1=" defaults.putBoolean(KEY_EMERGENCY_LTE_PREFERRED_AFTER_NR_FAILED_BOOL, false);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/CarrierConfigManager.java"
+ line="8100"
+ column="33"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `KEY_EMERGENCY_REQUIRES_VOLTE_ENABLED_BOOL` is a flagged API and should be inside an `if (Flags.useOemDomainSelectionService())` check (or annotate the surrounding method `getDefaults` with `@FlaggedApi(Flags.FLAG_USE_OEM_DOMAIN_SELECTION_SERVICE) to transfer requirement to caller`)"
+ errorLine1=" defaults.putBoolean(KEY_EMERGENCY_REQUIRES_VOLTE_ENABLED_BOOL, false);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/CarrierConfigManager.java"
+ line="8101"
+ column="33"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `KEY_EMERGENCY_CDMA_PREFERRED_NUMBERS_STRING_ARRAY` is a flagged API and should be inside an `if (Flags.useOemDomainSelectionService())` check (or annotate the surrounding method `getDefaults` with `@FlaggedApi(Flags.FLAG_USE_OEM_DOMAIN_SELECTION_SERVICE) to transfer requirement to caller`)"
+ errorLine1=" defaults.putStringArray(KEY_EMERGENCY_CDMA_PREFERRED_NUMBERS_STRING_ARRAY,"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/CarrierConfigManager.java"
+ line="8102"
+ column="37"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `KEY_CROSS_STACK_REDIAL_TIMER_SEC_INT` is a flagged API and should be inside an `if (Flags.useOemDomainSelectionService())` check (or annotate the surrounding method `getDefaults` with `@FlaggedApi(Flags.FLAG_USE_OEM_DOMAIN_SELECTION_SERVICE) to transfer requirement to caller`)"
+ errorLine1=" defaults.putInt(KEY_CROSS_STACK_REDIAL_TIMER_SEC_INT, 120);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/CarrierConfigManager.java"
+ line="8104"
+ column="29"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `KEY_QUICK_CROSS_STACK_REDIAL_TIMER_SEC_INT` is a flagged API and should be inside an `if (Flags.useOemDomainSelectionService())` check (or annotate the surrounding method `getDefaults` with `@FlaggedApi(Flags.FLAG_USE_OEM_DOMAIN_SELECTION_SERVICE) to transfer requirement to caller`)"
+ errorLine1=" defaults.putInt(KEY_QUICK_CROSS_STACK_REDIAL_TIMER_SEC_INT, REDIAL_TIMER_DISABLED);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/CarrierConfigManager.java"
+ line="8105"
+ column="29"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `REDIAL_TIMER_DISABLED` is a flagged API and should be inside an `if (Flags.useOemDomainSelectionService())` check (or annotate the surrounding method `getDefaults` with `@FlaggedApi(Flags.FLAG_USE_OEM_DOMAIN_SELECTION_SERVICE) to transfer requirement to caller`)"
+ errorLine1=" defaults.putInt(KEY_QUICK_CROSS_STACK_REDIAL_TIMER_SEC_INT, REDIAL_TIMER_DISABLED);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/CarrierConfigManager.java"
+ line="8105"
+ column="73"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `KEY_START_QUICK_CROSS_STACK_REDIAL_TIMER_WHEN_REGISTERED_BOOL` is a flagged API and should be inside an `if (Flags.useOemDomainSelectionService())` check (or annotate the surrounding method `getDefaults` with `@FlaggedApi(Flags.FLAG_USE_OEM_DOMAIN_SELECTION_SERVICE) to transfer requirement to caller`)"
+ errorLine1=" defaults.putBoolean(KEY_START_QUICK_CROSS_STACK_REDIAL_TIMER_WHEN_REGISTERED_BOOL,"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/CarrierConfigManager.java"
+ line="8106"
+ column="33"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `KEY_SCAN_LIMITED_SERVICE_AFTER_VOLTE_FAILURE_BOOL` is a flagged API and should be inside an `if (Flags.useOemDomainSelectionService())` check (or annotate the surrounding method `getDefaults` with `@FlaggedApi(Flags.FLAG_USE_OEM_DOMAIN_SELECTION_SERVICE) to transfer requirement to caller`)"
+ errorLine1=" defaults.putBoolean(KEY_SCAN_LIMITED_SERVICE_AFTER_VOLTE_FAILURE_BOOL, false);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/CarrierConfigManager.java"
+ line="8108"
+ column="33"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `KEY_SUPPORTS_IKE_SESSION_MULTIPLE_SA_PROPOSALS_BOOL` is a flagged API and should be inside an `if (Flags.enableMultipleSaProposals())` check (or annotate the surrounding method `getDefaults` with `@FlaggedApi(Flags.FLAG_ENABLE_MULTIPLE_SA_PROPOSALS) to transfer requirement to caller`)"
+ errorLine1=" defaults.putBoolean(KEY_SUPPORTS_IKE_SESSION_MULTIPLE_SA_PROPOSALS_BOOL, false);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/CarrierConfigManager.java"
+ line="9405"
+ column="33"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `KEY_SUPPORTS_CHILD_SESSION_MULTIPLE_SA_PROPOSALS_BOOL` is a flagged API and should be inside an `if (Flags.enableMultipleSaProposals())` check (or annotate the surrounding method `getDefaults` with `@FlaggedApi(Flags.FLAG_ENABLE_MULTIPLE_SA_PROPOSALS) to transfer requirement to caller`)"
+ errorLine1=" defaults.putBoolean(KEY_SUPPORTS_CHILD_SESSION_MULTIPLE_SA_PROPOSALS_BOOL, false);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/CarrierConfigManager.java"
+ line="9406"
+ column="33"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `KEY_SUPPORTED_IKE_SESSION_AEAD_ALGORITHMS_INT_ARRAY` is a flagged API and should be inside an `if (Flags.enableAeadAlgorithms())` check (or annotate the surrounding method `getDefaults` with `@FlaggedApi(Flags.FLAG_ENABLE_AEAD_ALGORITHMS) to transfer requirement to caller`)"
+ errorLine1=" KEY_SUPPORTED_IKE_SESSION_AEAD_ALGORITHMS_INT_ARRAY, new int[] {});"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/CarrierConfigManager.java"
+ line="9422"
+ column="21"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `KEY_SUPPORTED_CHILD_SESSION_AEAD_ALGORITHMS_INT_ARRAY` is a flagged API and should be inside an `if (Flags.enableAeadAlgorithms())` check (or annotate the surrounding method `getDefaults` with `@FlaggedApi(Flags.FLAG_ENABLE_AEAD_ALGORITHMS) to transfer requirement to caller`)"
+ errorLine1=" KEY_SUPPORTED_CHILD_SESSION_AEAD_ALGORITHMS_INT_ARRAY, new int[] {});"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/CarrierConfigManager.java"
+ line="9427"
+ column="21"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `KEY_IKE_SESSION_AES_GCM_KEY_SIZE_INT_ARRAY` is a flagged API and should be inside an `if (Flags.enableAeadAlgorithms())` check (or annotate the surrounding method `getDefaults` with `@FlaggedApi(Flags.FLAG_ENABLE_AEAD_ALGORITHMS) to transfer requirement to caller`)"
+ errorLine1=" KEY_IKE_SESSION_AES_GCM_KEY_SIZE_INT_ARRAY, new int[] {});"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/CarrierConfigManager.java"
+ line="9477"
+ column="21"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `KEY_CHILD_SESSION_AES_GCM_KEY_SIZE_INT_ARRAY` is a flagged API and should be inside an `if (Flags.enableAeadAlgorithms())` check (or annotate the surrounding method `getDefaults` with `@FlaggedApi(Flags.FLAG_ENABLE_AEAD_ALGORITHMS) to transfer requirement to caller`)"
+ errorLine1=" KEY_CHILD_SESSION_AES_GCM_KEY_SIZE_INT_ARRAY, new int[] {});"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/CarrierConfigManager.java"
+ line="9479"
+ column="21"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `KEY_ADDITIONAL_SETTINGS_CALLER_ID_VISIBILITY_BOOL` is a flagged API and should be inside an `if (Flags.showCallIdAndCallWaitingInAdditionalSettingsMenu())` check (or annotate the surrounding method `?` with `@FlaggedApi(Flags.FLAG_SHOW_CALL_ID_AND_CALL_WAITING_IN_ADDITIONAL_SETTINGS_MENU) to transfer requirement to caller`)"
+ errorLine1=" sDefaults.putBoolean(KEY_ADDITIONAL_SETTINGS_CALLER_ID_VISIBILITY_BOOL, true);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/CarrierConfigManager.java"
+ line="10519"
+ column="30"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `KEY_ADDITIONAL_SETTINGS_CALL_WAITING_VISIBILITY_BOOL` is a flagged API and should be inside an `if (Flags.showCallIdAndCallWaitingInAdditionalSettingsMenu())` check (or annotate the surrounding method `?` with `@FlaggedApi(Flags.FLAG_SHOW_CALL_ID_AND_CALL_WAITING_IN_ADDITIONAL_SETTINGS_MENU) to transfer requirement to caller`)"
+ errorLine1=" sDefaults.putBoolean(KEY_ADDITIONAL_SETTINGS_CALL_WAITING_VISIBILITY_BOOL, true);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/CarrierConfigManager.java"
+ line="10520"
+ column="30"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `KEY_PREFER_3G_VISIBILITY_BOOL` is a flagged API and should be inside an `if (Flags.hidePrefer3gItem())` check (or annotate the surrounding method `?` with `@FlaggedApi(Flags.FLAG_HIDE_PREFER_3G_ITEM) to transfer requirement to caller`)"
+ errorLine1=" sDefaults.putBoolean(KEY_PREFER_3G_VISIBILITY_BOOL, true);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/CarrierConfigManager.java"
+ line="10526"
+ column="30"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `KEY_SHOW_ROAMING_INDICATOR_BOOL` is a flagged API and should be inside an `if (Flags.hideRoamingIcon())` check (or annotate the surrounding method `?` with `@FlaggedApi(Flags.FLAG_HIDE_ROAMING_ICON) to transfer requirement to caller`)"
+ errorLine1=" sDefaults.putBoolean(KEY_SHOW_ROAMING_INDICATOR_BOOL, true);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/CarrierConfigManager.java"
+ line="10794"
+ column="30"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `KEY_CARRIER_SUPPORTED_SATELLITE_SERVICES_PER_PROVIDER_BUNDLE` is a flagged API and should be inside an `if (Flags.carrierEnabledSatelliteFlag())` check (or annotate the surrounding method `?` with `@FlaggedApi(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG) to transfer requirement to caller`)"
+ errorLine1=" KEY_CARRIER_SUPPORTED_SATELLITE_SERVICES_PER_PROVIDER_BUNDLE,"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/CarrierConfigManager.java"
+ line="11093"
+ column="17"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `KEY_SATELLITE_ATTACH_SUPPORTED_BOOL` is a flagged API and should be inside an `if (Flags.carrierEnabledSatelliteFlag())` check (or annotate the surrounding method `?` with `@FlaggedApi(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG) to transfer requirement to caller`)"
+ errorLine1=" sDefaults.putBoolean(KEY_SATELLITE_ATTACH_SUPPORTED_BOOL, false);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/CarrierConfigManager.java"
+ line="11095"
+ column="30"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `KEY_SATELLITE_CONNECTION_HYSTERESIS_SEC_INT` is a flagged API and should be inside an `if (Flags.carrierEnabledSatelliteFlag())` check (or annotate the surrounding method `?` with `@FlaggedApi(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG) to transfer requirement to caller`)"
+ errorLine1=" sDefaults.putInt(KEY_SATELLITE_CONNECTION_HYSTERESIS_SEC_INT, 300);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/CarrierConfigManager.java"
+ line="11096"
+ column="26"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `KEY_NTN_LTE_RSRP_THRESHOLDS_INT_ARRAY` is a flagged API and should be inside an `if (Flags.carrierEnabledSatelliteFlag())` check (or annotate the surrounding method `?` with `@FlaggedApi(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG) to transfer requirement to caller`)"
+ errorLine1=" sDefaults.putIntArray(KEY_NTN_LTE_RSRP_THRESHOLDS_INT_ARRAY,"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/CarrierConfigManager.java"
+ line="11097"
+ column="31"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `KEY_NTN_LTE_RSRQ_THRESHOLDS_INT_ARRAY` is a flagged API and should be inside an `if (Flags.carrierEnabledSatelliteFlag())` check (or annotate the surrounding method `?` with `@FlaggedApi(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG) to transfer requirement to caller`)"
+ errorLine1=" sDefaults.putIntArray(KEY_NTN_LTE_RSRQ_THRESHOLDS_INT_ARRAY,"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/CarrierConfigManager.java"
+ line="11105"
+ column="31"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `KEY_NTN_LTE_RSSNR_THRESHOLDS_INT_ARRAY` is a flagged API and should be inside an `if (Flags.carrierEnabledSatelliteFlag())` check (or annotate the surrounding method `?` with `@FlaggedApi(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG) to transfer requirement to caller`)"
+ errorLine1=" sDefaults.putIntArray(KEY_NTN_LTE_RSSNR_THRESHOLDS_INT_ARRAY,"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/CarrierConfigManager.java"
+ line="11113"
+ column="31"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `KEY_PARAMETERS_USED_FOR_NTN_LTE_SIGNAL_BAR_INT` is a flagged API and should be inside an `if (Flags.carrierEnabledSatelliteFlag())` check (or annotate the surrounding method `?` with `@FlaggedApi(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG) to transfer requirement to caller`)"
+ errorLine1=" sDefaults.putInt(KEY_PARAMETERS_USED_FOR_NTN_LTE_SIGNAL_BAR_INT,"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/CarrierConfigManager.java"
+ line="11121"
+ column="26"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `KEY_SATELLITE_ENTITLEMENT_STATUS_REFRESH_DAYS_INT` is a flagged API and should be inside an `if (Flags.carrierEnabledSatelliteFlag())` check (or annotate the surrounding method `?` with `@FlaggedApi(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG) to transfer requirement to caller`)"
+ errorLine1=" sDefaults.putInt(KEY_SATELLITE_ENTITLEMENT_STATUS_REFRESH_DAYS_INT, 7);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/CarrierConfigManager.java"
+ line="11127"
+ column="26"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `KEY_SATELLITE_ENTITLEMENT_SUPPORTED_BOOL` is a flagged API and should be inside an `if (Flags.carrierEnabledSatelliteFlag())` check (or annotate the surrounding method `?` with `@FlaggedApi(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG) to transfer requirement to caller`)"
+ errorLine1=" sDefaults.putBoolean(KEY_SATELLITE_ENTITLEMENT_SUPPORTED_BOOL, false);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/CarrierConfigManager.java"
+ line="11128"
+ column="30"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `SERVICE_TYPE_MMS` is a flagged API and should be inside an `if (Flags.carrierEnabledSatelliteFlag())` check (or annotate the surrounding method `?` with `@FlaggedApi(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG) to transfer requirement to caller`)"
+ errorLine1=" NetworkRegistrationInfo.SERVICE_TYPE_MMS"
+ errorLine2=" ~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/CarrierConfigManager.java"
+ line="11134"
+ column="49"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `KEY_SUPPORTS_BUSINESS_CALL_COMPOSER_BOOL` is a flagged API and should be inside an `if (Flags.businessCallComposer())` check (or annotate the surrounding method `?` with `@FlaggedApi(Flags.FLAG_BUSINESS_CALL_COMPOSER) to transfer requirement to caller`)"
+ errorLine1=" sDefaults.putBoolean(KEY_SUPPORTS_BUSINESS_CALL_COMPOSER_BOOL, false);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/CarrierConfigManager.java"
+ line="11142"
+ column="30"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `KEY_CELLULAR_SERVICE_CAPABILITIES_INT_ARRAY` is a flagged API and should be inside an `if (Flags.dataOnlyCellularService())` check (or annotate the surrounding method `?` with `@FlaggedApi(Flags.FLAG_DATA_ONLY_CELLULAR_SERVICE) to transfer requirement to caller`)"
+ errorLine1=" sDefaults.putIntArray(KEY_CELLULAR_SERVICE_CAPABILITIES_INT_ARRAY, new int[]{1, 2, 3});"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/CarrierConfigManager.java"
+ line="11233"
+ column="31"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Class `TelephonyRegistryManager` is a flagged API and should be inside an `if (Flags.telecomResolveHiddenDependencies())` check (or annotate the surrounding method `registerCarrierConfigChangeListener` with `@FlaggedApi(Flags.FLAG_TELECOM_RESOLVE_HIDDEN_DEPENDENCIES) to transfer requirement to caller`)"
+ errorLine1=" TelephonyRegistryManager trm = mContext.getSystemService(TelephonyRegistryManager.class);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/CarrierConfigManager.java"
+ line="11771"
+ column="66"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `addCarrierConfigChangedListener()` is a flagged API and should be inside an `if (Flags.telecomResolveHiddenDependencies())` check (or annotate the surrounding method `registerCarrierConfigChangeListener` with `@FlaggedApi(Flags.FLAG_TELECOM_RESOLVE_HIDDEN_DEPENDENCIES) to transfer requirement to caller`)"
+ errorLine1=" trm.addCarrierConfigChangedListener(executor, listener);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/CarrierConfigManager.java"
+ line="11775"
+ column="9"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Class `TelephonyRegistryManager` is a flagged API and should be inside an `if (Flags.telecomResolveHiddenDependencies())` check (or annotate the surrounding method `unregisterCarrierConfigChangeListener` with `@FlaggedApi(Flags.FLAG_TELECOM_RESOLVE_HIDDEN_DEPENDENCIES) to transfer requirement to caller`)"
+ errorLine1=" TelephonyRegistryManager trm = mContext.getSystemService(TelephonyRegistryManager.class);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/CarrierConfigManager.java"
+ line="11789"
+ column="66"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `removeCarrierConfigChangedListener()` is a flagged API and should be inside an `if (Flags.telecomResolveHiddenDependencies())` check (or annotate the surrounding method `unregisterCarrierConfigChangeListener` with `@FlaggedApi(Flags.FLAG_TELECOM_RESOLVE_HIDDEN_DEPENDENCIES) to transfer requirement to caller`)"
+ errorLine1=" trm.removeCarrierConfigChangedListener(listener);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/CarrierConfigManager.java"
+ line="11793"
+ column="9"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="This is a flagged API and should be inside an `if (Flags.telecomResolveHiddenDependencies())` check (or annotate the surrounding method `notifyCarrierNetworkChange` with `@FlaggedApi(Flags.FLAG_TELECOM_RESOLVE_HIDDEN_DEPENDENCIES) to transfer requirement to caller`)"
+ errorLine1=" (TelephonyRegistryManager) this.getSystemService("
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/service/carrier/CarrierService.java"
+ line="180"
+ column="14"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `notifyCarrierNetworkChange()` is a flagged API and should be inside an `if (Flags.telecomResolveHiddenDependencies())` check (or annotate the surrounding method `notifyCarrierNetworkChange` with `@FlaggedApi(Flags.FLAG_TELECOM_RESOLVE_HIDDEN_DEPENDENCIES) to transfer requirement to caller`)"
+ errorLine1=" telephonyRegistryMgr.notifyCarrierNetworkChange(active);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/service/carrier/CarrierService.java"
+ line="183"
+ column="13"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Class `TelephonyRegistryManager` is a flagged API and should be inside an `if (Flags.telecomResolveHiddenDependencies())` check (or annotate the surrounding method `notifyCarrierNetworkChange` with `@FlaggedApi(Flags.FLAG_TELECOM_RESOLVE_HIDDEN_DEPENDENCIES) to transfer requirement to caller`)"
+ errorLine1=" TelephonyRegistryManager.class);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/service/carrier/CarrierService.java"
+ line="206"
+ column="17"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `notifyCarrierNetworkChange()` is a flagged API and should be inside an `if (Flags.telecomResolveHiddenDependencies())` check (or annotate the surrounding method `notifyCarrierNetworkChange` with `@FlaggedApi(Flags.FLAG_TELECOM_RESOLVE_HIDDEN_DEPENDENCIES) to transfer requirement to caller`)"
+ errorLine1=" telephonyRegistryMgr.notifyCarrierNetworkChange(subscriptionId, active);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/service/carrier/CarrierService.java"
+ line="208"
+ column="13"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `isUsingNonTerrestrialNetwork()` is a flagged API and should be inside an `if (Flags.carrierEnabledSatelliteFlag())` check (or annotate the surrounding method `updateLevel` with `@FlaggedApi(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG) to transfer requirement to caller`)"
+ errorLine1=" if (ss != null && ss.isUsingNonTerrestrialNetwork()) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/CellSignalStrengthLte.java"
+ line="266"
+ column="31"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `KEY_PARAMETERS_USED_FOR_NTN_LTE_SIGNAL_BAR_INT` is a flagged API and should be inside an `if (Flags.carrierEnabledSatelliteFlag())` check (or annotate the surrounding method `updateLevel` with `@FlaggedApi(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG) to transfer requirement to caller`)"
+ errorLine1=" CarrierConfigManager.KEY_PARAMETERS_USED_FOR_NTN_LTE_SIGNAL_BAR_INT);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/CellSignalStrengthLte.java"
+ line="269"
+ column="46"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `KEY_NTN_LTE_RSRP_THRESHOLDS_INT_ARRAY` is a flagged API and should be inside an `if (Flags.carrierEnabledSatelliteFlag())` check (or annotate the surrounding method `updateLevel` with `@FlaggedApi(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG) to transfer requirement to caller`)"
+ errorLine1=" CarrierConfigManager.KEY_NTN_LTE_RSRP_THRESHOLDS_INT_ARRAY);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/CellSignalStrengthLte.java"
+ line="271"
+ column="46"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `KEY_NTN_LTE_RSRQ_THRESHOLDS_INT_ARRAY` is a flagged API and should be inside an `if (Flags.carrierEnabledSatelliteFlag())` check (or annotate the surrounding method `updateLevel` with `@FlaggedApi(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG) to transfer requirement to caller`)"
+ errorLine1=" CarrierConfigManager.KEY_NTN_LTE_RSRQ_THRESHOLDS_INT_ARRAY);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/CellSignalStrengthLte.java"
+ line="273"
+ column="46"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `KEY_NTN_LTE_RSSNR_THRESHOLDS_INT_ARRAY` is a flagged API and should be inside an `if (Flags.carrierEnabledSatelliteFlag())` check (or annotate the surrounding method `updateLevel` with `@FlaggedApi(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG) to transfer requirement to caller`)"
+ errorLine1=" CarrierConfigManager.KEY_NTN_LTE_RSSNR_THRESHOLDS_INT_ARRAY);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/CellSignalStrengthLte.java"
+ line="275"
+ column="46"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `getFrameTimeNanos()` is a flagged API and should be inside an `if (Flags.expectedPresentationTimeApi())` check (or annotate the surrounding method `getFrameTime` with `@FlaggedApi(Flags.FLAG_EXPECTED_PRESENTATION_TIME_API) to transfer requirement to caller`)"
+ errorLine1=" return getFrameTimeNanos() / TimeUtils.NANOS_PER_MS;"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/view/Choreographer.java"
+ line="694"
+ column="16"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `lockAnimationClock()` is a flagged API and should be inside an `if (Flags.expectedPresentationTimeReadOnly())` check (or annotate the surrounding method `doFrame` with `@FlaggedApi(Flags.FLAG_EXPECTED_PRESENTATION_TIME_READ_ONLY) to transfer requirement to caller`)"
+ errorLine1=" AnimationUtils.lockAnimationClock(frameTimeNanos / TimeUtils.NANOS_PER_MS,"
+ errorLine2=" ^">
+ <location
+ file="frameworks/base/core/java/android/view/Choreographer.java"
+ line="934"
+ column="13"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `SOURCE_UNKNOWN` is a flagged API and should be inside an `if (Flags.modesApi())` check (or annotate the surrounding method `Condition` with `@FlaggedApi(Flags.FLAG_MODES_API) to transfer requirement to caller`)"
+ errorLine1=" this(id, summary, "", "", -1, state, SOURCE_UNKNOWN, FLAG_RELEVANT_ALWAYS);"
+ errorLine2=" ~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/service/notification/Condition.java"
+ line="138"
+ column="46"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `Condition()` is a flagged API and should be inside an `if (Flags.modesApi())` check (or annotate the surrounding method `Condition` with `@FlaggedApi(Flags.FLAG_MODES_API) to transfer requirement to caller`)"
+ errorLine1=" this(id, summary, "", "", -1, state, SOURCE_UNKNOWN, FLAG_RELEVANT_ALWAYS);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/service/notification/Condition.java"
+ line="138"
+ column="9"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `SOURCE_UNKNOWN` is a flagged API and should be inside an `if (Flags.modesApi())` check (or annotate the surrounding method `Condition` with `@FlaggedApi(Flags.FLAG_MODES_API) to transfer requirement to caller`)"
+ errorLine1=" this(id, summary, line1, line2, icon, state, SOURCE_UNKNOWN, flags);"
+ errorLine2=" ~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/service/notification/Condition.java"
+ line="157"
+ column="54"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `Condition()` is a flagged API and should be inside an `if (Flags.modesApi())` check (or annotate the surrounding method `Condition` with `@FlaggedApi(Flags.FLAG_MODES_API) to transfer requirement to caller`)"
+ errorLine1=" this(id, summary, line1, line2, icon, state, SOURCE_UNKNOWN, flags);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/service/notification/Condition.java"
+ line="157"
+ column="9"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `Condition()` is a flagged API and should be inside an `if (Flags.modesApi())` check (or annotate the surrounding method `Condition` with `@FlaggedApi(Flags.FLAG_MODES_API) to transfer requirement to caller`)"
+ errorLine1=" this((Uri)source.readParcelable(Condition.class.getClassLoader(), android.net.Uri.class),"
+ errorLine2=" ^">
+ <location
+ file="frameworks/base/core/java/android/service/notification/Condition.java"
+ line="192"
+ column="9"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `SOURCE_UNKNOWN` is a flagged API and should be inside an `if (Flags.modesApi())` check (or annotate the surrounding method `Condition` with `@FlaggedApi(Flags.FLAG_MODES_API) to transfer requirement to caller`)"
+ errorLine1=" Flags.modesApi() ? source.readInt() : SOURCE_UNKNOWN,"
+ errorLine2=" ~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/service/notification/Condition.java"
+ line="198"
+ column="55"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `onCreateConnectionComplete()` is a flagged API and should be inside an `if (Flags.telecomResolveHiddenDependencies())` check (or annotate the surrounding method `notifyCreateConnectionComplete` with `@FlaggedApi(Flags.FLAG_TELECOM_RESOLVE_HIDDEN_DEPENDENCIES) to transfer requirement to caller`)"
+ errorLine1=" onCreateConnectionComplete(findConnectionForAction(callId,"
+ errorLine2=" ^">
+ <location
+ file="frameworks/base/telecomm/java/android/telecom/ConnectionService.java"
+ line="2531"
+ column="9"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `onCreateConferenceComplete()` is a flagged API and should be inside an `if (Flags.telecomResolveHiddenDependencies())` check (or annotate the surrounding method `notifyCreateConferenceComplete` with `@FlaggedApi(Flags.FLAG_TELECOM_RESOLVE_HIDDEN_DEPENDENCIES) to transfer requirement to caller`)"
+ errorLine1=" onCreateConferenceComplete(findConferenceForAction(callId,"
+ errorLine2=" ^">
+ <location
+ file="frameworks/base/telecomm/java/android/telecom/ConnectionService.java"
+ line="2548"
+ column="9"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `getCallDirection()` is a flagged API and should be inside an `if (Flags.telecomResolveHiddenDependencies())` check (or annotate the surrounding method `addExistingConnection` with `@FlaggedApi(Flags.FLAG_TELECOM_RESOLVE_HIDDEN_DEPENDENCIES) to transfer requirement to caller`)"
+ errorLine1=" connection.getCallDirection(),"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telecomm/java/android/telecom/ConnectionService.java"
+ line="3179"
+ column="21"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `supportsReliableMessages()` is a flagged API and should be inside an `if (Flags.reliableMessage())` check (or annotate the surrounding method `equals` with `@FlaggedApi(Flags.FLAG_RELIABLE_MESSAGE) to transfer requirement to caller`)"
+ errorLine1=" || (other.supportsReliableMessages() == mSupportsReliableMessages))"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/hardware/location/ContextHubInfo.java"
+ line="365"
+ column="33"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `isReliable()` is a flagged API and should be inside an `if (Flags.reliableMessage())` check (or annotate the surrounding method `onMessageFromNanoApp` with `@FlaggedApi(Flags.FLAG_RELIABLE_MESSAGE) to transfer requirement to caller`)"
+ errorLine1=" && message.isReliable()) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/hardware/location/ContextHubManager.java"
+ line="715"
+ column="44"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `TYPE_RELIABLE_MESSAGE` is a flagged API and should be inside an `if (Flags.reliableMessage())` check (or annotate the surrounding method `typeToString` with `@FlaggedApi(Flags.FLAG_RELIABLE_MESSAGE) to transfer requirement to caller`)"
+ errorLine1=" case ContextHubTransaction.TYPE_RELIABLE_MESSAGE: {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/hardware/location/ContextHubTransaction.java"
+ line="235"
+ column="40"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `shouldRegisterAttributionSource()` is a flagged API and should be inside an `if (Flags.shouldRegisterAttributionSource())` check (or annotate the surrounding method `ContextImpl` with `@FlaggedApi(Flags.FLAG_SHOULD_REGISTER_ATTRIBUTION_SOURCE) to transfer requirement to caller`)"
+ errorLine1=" params.getRenouncedPermissions(), params.shouldRegisterAttributionSource(), mDeviceId);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/app/ContextImpl.java"
+ line="3540"
+ column="51"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `NETWORK_VALIDATION_UNSUPPORTED` is a flagged API and should be inside an `if (Flags.networkValidation())` check (or annotate the surrounding method `DataCallResponse` with `@FlaggedApi(Flags.FLAG_NETWORK_VALIDATION) to transfer requirement to caller`)"
+ errorLine1=" PreciseDataConnectionState.NETWORK_VALIDATION_UNSUPPORTED);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/data/DataCallResponse.java"
+ line="192"
+ column="44"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `NETWORK_VALIDATION_UNSUPPORTED` is a flagged API and should be inside an `if (Flags.networkValidation())` check (or annotate the surrounding method `?` with `@FlaggedApi(Flags.FLAG_NETWORK_VALIDATION) to transfer requirement to caller`)"
+ errorLine1=" PreciseDataConnectionState.NETWORK_VALIDATION_UNSUPPORTED;"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/data/DataCallResponse.java"
+ line="655"
+ column="44"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `TYPE_RCS` is a flagged API and should be inside an `if (Flags.carrierEnabledSatelliteFlag())` check (or annotate the surrounding method `networkCapabilityToApnType` with `@FlaggedApi(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG) to transfer requirement to caller`)"
+ errorLine1=" return ApnSetting.TYPE_RCS;"
+ errorLine2=" ~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/data/DataProfile.java"
+ line="435"
+ column="35"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `requestNetworkValidation()` is a flagged API and should be inside an `if (Flags.networkValidation())` check (or annotate the surrounding method `handleMessage` with `@FlaggedApi(Flags.FLAG_NETWORK_VALIDATION) to transfer requirement to caller`)"
+ errorLine1=" serviceProvider.requestNetworkValidation("
+ errorLine2=" ^">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/data/DataService.java"
+ line="744"
+ column="21"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `HEADLESS_DEVICE_OWNER_MODE_SINGLE_USER` is a flagged API and should be inside an `if (Flags.headlessDeviceOwnerSingleUserEnabled())` check (or annotate the surrounding method `DeviceAdminInfo` with `@FlaggedApi(Flags.FLAG_HEADLESS_DEVICE_OWNER_SINGLE_USER_ENABLED) to transfer requirement to caller`)"
+ errorLine1=" mHeadlessDeviceOwnerMode = HEADLESS_DEVICE_OWNER_MODE_SINGLE_USER;"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/app/admin/DeviceAdminInfo.java"
+ line="410"
+ column="52"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `CONTENT_PROTECTION_DISABLED` is a flagged API and should be inside an `if (Flags.manageDevicePolicyEnabled())` check (or annotate the surrounding method `getContentProtectionPolicy` with `@FlaggedApi(Flags.FLAG_MANAGE_DEVICE_POLICY_ENABLED) to transfer requirement to caller`)"
+ errorLine1=" return CONTENT_PROTECTION_DISABLED;"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/app/admin/DevicePolicyCache.java"
+ line="105"
+ column="20"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `equals()` is a flagged API and should be inside an `if (Flags.deviceStatePropertyApi())` check (or annotate the surrounding method `equals` with `@FlaggedApi(Flags.FLAG_DEVICE_STATE_PROPERTY_API) to transfer requirement to caller`)"
+ errorLine1=" return baseState.equals(that.baseState)"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/hardware/devicestate/DeviceStateInfo.java"
+ line="101"
+ column="16"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `equals()` is a flagged API and should be inside an `if (Flags.deviceStatePropertyApi())` check (or annotate the surrounding method `equals` with `@FlaggedApi(Flags.FLAG_DEVICE_STATE_PROPERTY_API) to transfer requirement to caller`)"
+ errorLine1=" && currentState.equals(that.currentState)"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/hardware/devicestate/DeviceStateInfo.java"
+ line="102"
+ column="21"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `equals()` is a flagged API and should be inside an `if (Flags.deviceStatePropertyApi())` check (or annotate the surrounding method `diff` with `@FlaggedApi(Flags.FLAG_DEVICE_STATE_PROPERTY_API) to transfer requirement to caller`)"
+ errorLine1=" if (!baseState.equals(other.baseState)) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/hardware/devicestate/DeviceStateInfo.java"
+ line="120"
+ column="14"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `equals()` is a flagged API and should be inside an `if (Flags.deviceStatePropertyApi())` check (or annotate the surrounding method `diff` with `@FlaggedApi(Flags.FLAG_DEVICE_STATE_PROPERTY_API) to transfer requirement to caller`)"
+ errorLine1=" if (!currentState.equals(other.currentState)) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/hardware/devicestate/DeviceStateInfo.java"
+ line="123"
+ column="14"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `getConfiguration()` is a flagged API and should be inside an `if (Flags.deviceStatePropertyApi())` check (or annotate the surrounding method `writeToParcel` with `@FlaggedApi(Flags.FLAG_DEVICE_STATE_PROPERTY_API) to transfer requirement to caller`)"
+ errorLine1=" dest.writeTypedObject(supportedStates.get(i).getConfiguration(), flags);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/hardware/devicestate/DeviceStateInfo.java"
+ line="133"
+ column="35"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `getConfiguration()` is a flagged API and should be inside an `if (Flags.deviceStatePropertyApi())` check (or annotate the surrounding method `writeToParcel` with `@FlaggedApi(Flags.FLAG_DEVICE_STATE_PROPERTY_API) to transfer requirement to caller`)"
+ errorLine1=" dest.writeTypedObject(baseState.getConfiguration(), flags);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/hardware/devicestate/DeviceStateInfo.java"
+ line="136"
+ column="31"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `getConfiguration()` is a flagged API and should be inside an `if (Flags.deviceStatePropertyApi())` check (or annotate the surrounding method `writeToParcel` with `@FlaggedApi(Flags.FLAG_DEVICE_STATE_PROPERTY_API) to transfer requirement to caller`)"
+ errorLine1=" dest.writeTypedObject(currentState.getConfiguration(), flags);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/hardware/devicestate/DeviceStateInfo.java"
+ line="137"
+ column="31"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `CREATOR` is a flagged API and should be inside an `if (Flags.deviceStatePropertyApi())` check (or annotate the surrounding method `createFromParcel` with `@FlaggedApi(Flags.FLAG_DEVICE_STATE_PROPERTY_API) to transfer requirement to caller`)"
+ errorLine1=" DeviceState.Configuration.CREATOR);"
+ errorLine2=" ~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/hardware/devicestate/DeviceStateInfo.java"
+ line="152"
+ column="51"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `DeviceState()` is a flagged API and should be inside an `if (Flags.deviceStatePropertyApi())` check (or annotate the surrounding method `createFromParcel` with `@FlaggedApi(Flags.FLAG_DEVICE_STATE_PROPERTY_API) to transfer requirement to caller`)"
+ errorLine1=" supportedStates.add(i, new DeviceState(configuration));"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/hardware/devicestate/DeviceStateInfo.java"
+ line="153"
+ column="40"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `DeviceState()` is a flagged API and should be inside an `if (Flags.deviceStatePropertyApi())` check (or annotate the surrounding method `createFromParcel` with `@FlaggedApi(Flags.FLAG_DEVICE_STATE_PROPERTY_API) to transfer requirement to caller`)"
+ errorLine1=" final DeviceState baseState = new DeviceState("
+ errorLine2=" ^">
+ <location
+ file="frameworks/base/core/java/android/hardware/devicestate/DeviceStateInfo.java"
+ line="156"
+ column="43"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `CREATOR` is a flagged API and should be inside an `if (Flags.deviceStatePropertyApi())` check (or annotate the surrounding method `createFromParcel` with `@FlaggedApi(Flags.FLAG_DEVICE_STATE_PROPERTY_API) to transfer requirement to caller`)"
+ errorLine1=" source.readTypedObject(DeviceState.Configuration.CREATOR));"
+ errorLine2=" ~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/hardware/devicestate/DeviceStateInfo.java"
+ line="157"
+ column="70"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `DeviceState()` is a flagged API and should be inside an `if (Flags.deviceStatePropertyApi())` check (or annotate the surrounding method `createFromParcel` with `@FlaggedApi(Flags.FLAG_DEVICE_STATE_PROPERTY_API) to transfer requirement to caller`)"
+ errorLine1=" final DeviceState currentState = new DeviceState("
+ errorLine2=" ^">
+ <location
+ file="frameworks/base/core/java/android/hardware/devicestate/DeviceStateInfo.java"
+ line="158"
+ column="46"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `CREATOR` is a flagged API and should be inside an `if (Flags.deviceStatePropertyApi())` check (or annotate the surrounding method `createFromParcel` with `@FlaggedApi(Flags.FLAG_DEVICE_STATE_PROPERTY_API) to transfer requirement to caller`)"
+ errorLine1=" source.readTypedObject(DeviceState.Configuration.CREATOR));"
+ errorLine2=" ~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/hardware/devicestate/DeviceStateInfo.java"
+ line="159"
+ column="70"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `onSupportedStatesChanged()` is a flagged API and should be inside an `if (Flags.deviceStatePropertyApi())` check (or annotate the surrounding method `notifySupportedDeviceStatesChanged` with `@FlaggedApi(Flags.FLAG_DEVICE_STATE_PROPERTY_API) to transfer requirement to caller`)"
+ errorLine1=" mDeviceStateCallback.onSupportedStatesChanged(newSupportedDeviceStates));"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/hardware/devicestate/DeviceStateManagerGlobal.java"
+ line="393"
+ column="21"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `onDeviceStateChanged()` is a flagged API and should be inside an `if (Flags.deviceStatePropertyApi())` check (or annotate the surrounding method `notifyDeviceStateChanged` with `@FlaggedApi(Flags.FLAG_DEVICE_STATE_PROPERTY_API) to transfer requirement to caller`)"
+ errorLine1=" () -> mDeviceStateCallback.onDeviceStateChanged(newDeviceState));"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/hardware/devicestate/DeviceStateManagerGlobal.java"
+ line="398"
+ column="27"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `getConfiguration()` is a flagged API and should be inside an `if (Flags.deviceStatePropertyApi())` check (or annotate the surrounding method `calculateBaseStateIdentifier` with `@FlaggedApi(Flags.FLAG_DEVICE_STATE_PROPERTY_API) to transfer requirement to caller`)"
+ errorLine1=" DeviceState.Configuration stateConfiguration = currentState.getConfiguration();"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/hardware/devicestate/DeviceStateUtil.java"
+ line="45"
+ column="56"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `getConfiguration()` is a flagged API and should be inside an `if (Flags.deviceStatePropertyApi())` check (or annotate the surrounding method `calculateBaseStateIdentifier` with `@FlaggedApi(Flags.FLAG_DEVICE_STATE_PROPERTY_API) to transfer requirement to caller`)"
+ errorLine1=" if (stateToCompare.getConfiguration().getPhysicalProperties().isEmpty()) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/hardware/devicestate/DeviceStateUtil.java"
+ line="48"
+ column="17"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `getPhysicalProperties()` is a flagged API and should be inside an `if (Flags.deviceStatePropertyApi())` check (or annotate the surrounding method `calculateBaseStateIdentifier` with `@FlaggedApi(Flags.FLAG_DEVICE_STATE_PROPERTY_API) to transfer requirement to caller`)"
+ errorLine1=" if (stateToCompare.getConfiguration().getPhysicalProperties().isEmpty()) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/hardware/devicestate/DeviceStateUtil.java"
+ line="48"
+ column="17"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `getPhysicalProperties()` is a flagged API and should be inside an `if (Flags.deviceStatePropertyApi())` check (or annotate the surrounding method `calculateBaseStateIdentifier` with `@FlaggedApi(Flags.FLAG_DEVICE_STATE_PROPERTY_API) to transfer requirement to caller`)"
+ errorLine1=" if (isDeviceStateMatchingPhysicalProperties(stateConfiguration.getPhysicalProperties(),"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/hardware/devicestate/DeviceStateUtil.java"
+ line="51"
+ column="57"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `getIdentifier()` is a flagged API and should be inside an `if (Flags.deviceStatePropertyApi())` check (or annotate the surrounding method `calculateBaseStateIdentifier` with `@FlaggedApi(Flags.FLAG_DEVICE_STATE_PROPERTY_API) to transfer requirement to caller`)"
+ errorLine1=" return supportedStates.get(i).getIdentifier();"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/hardware/devicestate/DeviceStateUtil.java"
+ line="53"
+ column="24"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `INVALID_DEVICE_STATE_IDENTIFIER` is a flagged API and should be inside an `if (Flags.deviceStatePropertyApi())` check (or annotate the surrounding method `calculateBaseStateIdentifier` with `@FlaggedApi(Flags.FLAG_DEVICE_STATE_PROPERTY_API) to transfer requirement to caller`)"
+ errorLine1=" return INVALID_DEVICE_STATE_IDENTIFIER;"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/hardware/devicestate/DeviceStateUtil.java"
+ line="56"
+ column="16"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `hasProperty()` is a flagged API and should be inside an `if (Flags.deviceStatePropertyApi())` check (or annotate the surrounding method `isDeviceStateMatchingPhysicalProperties` with `@FlaggedApi(Flags.FLAG_DEVICE_STATE_PROPERTY_API) to transfer requirement to caller`)"
+ errorLine1=" if (!state.hasProperty(iterator.next())) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/hardware/devicestate/DeviceStateUtil.java"
+ line="69"
+ column="18"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `getTelephonyDisconnectCause()` is a flagged API and should be inside an `if (Flags.telecomResolveHiddenDependencies())` check (or annotate the surrounding method `equals` with `@FlaggedApi(Flags.FLAG_TELECOM_RESOLVE_HIDDEN_DEPENDENCIES) to transfer requirement to caller`)"
+ errorLine1=" && Objects.equals(mTelephonyDisconnectCause, d.getTelephonyDisconnectCause())"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telecomm/java/android/telecom/DisconnectCause.java"
+ line="498"
+ column="66"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `getTelephonyPreciseDisconnectCause()` is a flagged API and should be inside an `if (Flags.telecomResolveHiddenDependencies())` check (or annotate the surrounding method `equals` with `@FlaggedApi(Flags.FLAG_TELECOM_RESOLVE_HIDDEN_DEPENDENCIES) to transfer requirement to caller`)"
+ errorLine1=" d.getTelephonyPreciseDisconnectCause())"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telecomm/java/android/telecom/DisconnectCause.java"
+ line="500"
+ column="21"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `getImsReasonInfo()` is a flagged API and should be inside an `if (Flags.telecomResolveHiddenDependencies())` check (or annotate the surrounding method `equals` with `@FlaggedApi(Flags.FLAG_TELECOM_RESOLVE_HIDDEN_DEPENDENCIES) to transfer requirement to caller`)"
+ errorLine1=" && Objects.equals(mImsReasonInfo, d.getImsReasonInfo());"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telecomm/java/android/telecom/DisconnectCause.java"
+ line="501"
+ column="55"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `SATELLITE_ENABLED` is a flagged API and should be inside an `if (Flags.oemEnabledSatelliteFlag())` check (or annotate the surrounding method `toString` with `@FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG) to transfer requirement to caller`)"
+ errorLine1=" case SATELLITE_ENABLED:"
+ errorLine2=" ~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/DisconnectCause.java"
+ line="550"
+ column="18"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `dreamCategory` is a flagged API and should be inside an `if (Flags.homePanelDream())` check (or annotate the surrounding method `DreamMetadata` with `@FlaggedApi(Flags.FLAG_HOME_PANEL_DREAM) to transfer requirement to caller`)"
+ errorLine1=" this.dreamCategory = DREAM_CATEGORY_DEFAULT;"
+ errorLine2=" ~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/service/dreams/DreamService.java"
+ line="1825"
+ column="22"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `setMinimumFontMetrics()` is a flagged API and should be inside an `if (Flags.fixLineHeightForLocale())` check (or annotate the surrounding method `reflow` with `@FlaggedApi(Flags.FLAG_FIX_LINE_HEIGHT_FOR_LOCALE) to transfer requirement to caller`)"
+ errorLine1=" b.setText(text, where, where + after)"
+ errorLine2=" ^">
+ <location
+ file="frameworks/base/core/java/android/text/DynamicLayout.java"
+ line="736"
+ column="9"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `setShiftDrawingOffsetForStartOverhang()` is a flagged API and should be inside an `if (Flags.useBoundsForWidth())` check (or annotate the surrounding method `reflow` with `@FlaggedApi(Flags.FLAG_USE_BOUNDS_FOR_WIDTH) to transfer requirement to caller`)"
+ errorLine1=" b.setText(text, where, where + after)"
+ errorLine2=" ^">
+ <location
+ file="frameworks/base/core/java/android/text/DynamicLayout.java"
+ line="736"
+ column="9"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `setUseBoundsForWidth()` is a flagged API and should be inside an `if (Flags.useBoundsForWidth())` check (or annotate the surrounding method `reflow` with `@FlaggedApi(Flags.FLAG_USE_BOUNDS_FOR_WIDTH) to transfer requirement to caller`)"
+ errorLine1=" b.setText(text, where, where + after)"
+ errorLine2=" ^">
+ <location
+ file="frameworks/base/core/java/android/text/DynamicLayout.java"
+ line="736"
+ column="9"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `getTextDirectionHeuristic()` is a flagged API and should be inside an `if (Flags.useBoundsForWidth())` check (or annotate the surrounding method `reflow` with `@FlaggedApi(Flags.FLAG_USE_BOUNDS_FOR_WIDTH) to transfer requirement to caller`)"
+ errorLine1=" .setTextDirection(getTextDirectionHeuristic())"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/text/DynamicLayout.java"
+ line="739"
+ column="35"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `setLocalePreferredLineHeightForMinimumUsed()` is a flagged API and should be inside an `if (Flags.fixLineHeightForLocale())` check (or annotate the surrounding method `EditText` with `@FlaggedApi(Flags.FLAG_FIX_LINE_HEIGHT_FOR_LOCALE) to transfer requirement to caller`)"
+ errorLine1=" setLocalePreferredLineHeightForMinimumUsed(useLocalePreferredLineHeightForMinimumInt);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/widget/EditText.java"
+ line="150"
+ column="9"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `convertSpToDp()` is a flagged API and should be inside an `if (Flags.fontScaleConverterPublic())` check (or annotate the surrounding method `createInterpolatedTableBetween` with `@FlaggedApi(Flags.FLAG_FONT_SCALE_CONVERTER_PUBLIC) to transfer requirement to caller`)"
+ errorLine1=" float startDp = start.convertSpToDp(sp);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/content/res/FontScaleConverterFactory.java"
+ line="242"
+ column="29"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `convertSpToDp()` is a flagged API and should be inside an `if (Flags.fontScaleConverterPublic())` check (or annotate the surrounding method `createInterpolatedTableBetween` with `@FlaggedApi(Flags.FLAG_FONT_SCALE_CONVERTER_PUBLIC) to transfer requirement to caller`)"
+ errorLine1=" float endDp = end.convertSpToDp(sp);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/content/res/FontScaleConverterFactory.java"
+ line="243"
+ column="27"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="This is a flagged API and should be inside an `if (Flags.fontScaleConverterPublic())` check (or annotate the surrounding method `?` with `@FlaggedApi(Flags.FLAG_FONT_SCALE_CONVERTER_PUBLIC) to transfer requirement to caller`)"
+ errorLine1="public class FontScaleConverterImpl implements FontScaleConverter {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/content/res/FontScaleConverterImpl.java"
+ line="36"
+ column="48"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `FOREGROUND_SERVICE_TYPE_MEDIA_PROCESSING` is a flagged API and should be inside an `if (Flags.introduceMediaProcessingType())` check (or annotate the surrounding method `?` with `@FlaggedApi(Flags.FLAG_INTRODUCE_MEDIA_PROCESSING_TYPE) to transfer requirement to caller`)"
+ errorLine1=" FOREGROUND_SERVICE_TYPE_MEDIA_PROCESSING,"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/app/ForegroundServiceTypePolicy.java"
+ line="587"
+ column="21"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `FOREGROUND_SERVICE_TYPE_MEDIA_PROCESSING` is a flagged API and should be inside an `if (Flags.introduceMediaProcessingType())` check (or annotate the surrounding method `DefaultForegroundServiceTypePolicy` with `@FlaggedApi(Flags.FLAG_INTRODUCE_MEDIA_PROCESSING_TYPE) to transfer requirement to caller`)"
+ errorLine1=" mForegroundServiceTypePolicies.put(FOREGROUND_SERVICE_TYPE_MEDIA_PROCESSING,"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/app/ForegroundServiceTypePolicy.java"
+ line="1355"
+ column="48"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `InputTransferToken()` is a flagged API and should be inside an `if (Flags.surfaceControlInputReceiver())` check (or annotate the surrounding method `doCreate` with `@FlaggedApi(Flags.FLAG_SURFACE_CONTROL_INPUT_RECEIVER) to transfer requirement to caller`)"
+ errorLine1=" new InputTransferToken(), "GameSessionService");"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/service/games/GameSessionService.java"
+ line="127"
+ column="25"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `CREATOR` is a flagged API and should be inside an `if (Flags.configurableSelectorUiEnabled())` check (or annotate the surrounding method `GetCandidateCredentialsResponse` with `@FlaggedApi(Flags.FLAG_CONFIGURABLE_SELECTOR_UI_ENABLED) to transfer requirement to caller`)"
+ errorLine1=" in.readTypedList(candidateProviderDataList, GetCredentialProviderData.CREATOR);"
+ errorLine2=" ~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/credentials/GetCandidateCredentialsResponse.java"
+ line="98"
+ column="79"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `isConnectionlessStylusHandwritingAvailable()` is a flagged API and should be inside an `if (Flags.connectionlessHandwriting())` check (or annotate the surrounding method `prepareDelegation` with `@FlaggedApi(Flags.FLAG_CONNECTIONLESS_HANDWRITING) to transfer requirement to caller`)"
+ errorLine1=" if (mImm.isConnectionlessStylusHandwritingAvailable()) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/view/HandwritingInitiator.java"
+ line="450"
+ column="13"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `startConnectionlessStylusHandwritingForDelegation()` is a flagged API and should be inside an `if (Flags.connectionlessHandwriting())` check (or annotate the surrounding method `prepareDelegation` with `@FlaggedApi(Flags.FLAG_CONNECTIONLESS_HANDWRITING) to transfer requirement to caller`)"
+ errorLine1=" mImm.startConnectionlessStylusHandwritingForDelegation("
+ errorLine2=" ^">
+ <location
+ file="frameworks/base/core/java/android/view/HandwritingInitiator.java"
+ line="454"
+ column="13"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="This is a flagged API and should be inside an `if (Flags.connectionlessHandwriting())` check (or annotate the surrounding method `?` with `@FlaggedApi(Flags.FLAG_CONNECTIONLESS_HANDWRITING) to transfer requirement to caller`)"
+ errorLine1=" private class DelegationCallback implements ConnectionlessHandwritingCallback {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/view/HandwritingInitiator.java"
+ line="1116"
+ column="49"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `CONNECTIONLESS_HANDWRITING_ERROR_NO_TEXT_RECOGNIZED` is a flagged API and should be inside an `if (Flags.connectionlessHandwriting())` check (or annotate the surrounding method `onError` with `@FlaggedApi(Flags.FLAG_CONNECTIONLESS_HANDWRITING) to transfer requirement to caller`)"
+ errorLine1=" case CONNECTIONLESS_HANDWRITING_ERROR_NO_TEXT_RECOGNIZED:"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/view/HandwritingInitiator.java"
+ line="1133"
+ column="22"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `CONNECTIONLESS_HANDWRITING_ERROR_UNSUPPORTED` is a flagged API and should be inside an `if (Flags.connectionlessHandwriting())` check (or annotate the surrounding method `onError` with `@FlaggedApi(Flags.FLAG_CONNECTIONLESS_HANDWRITING) to transfer requirement to caller`)"
+ errorLine1=" case CONNECTIONLESS_HANDWRITING_ERROR_UNSUPPORTED:"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/view/HandwritingInitiator.java"
+ line="1136"
+ column="22"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="This is a flagged API and should be inside an `if (Flags.scrollFeedbackApi())` check (or annotate the surrounding method `?` with `@FlaggedApi(Flags.FLAG_SCROLL_FEEDBACK_API) to transfer requirement to caller`)"
+ errorLine1="public class HapticScrollFeedbackProvider implements ScrollFeedbackProvider {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/view/HapticScrollFeedbackProvider.java"
+ line="36"
+ column="54"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `getOverlaySupport()` is a flagged API and should be inside an `if (Flags.overlaypropertiesClassApi())` check (or annotate the surrounding method `initDisplayInfo` with `@FlaggedApi(Flags.FLAG_OVERLAYPROPERTIES_CLASS_API) to transfer requirement to caller`)"
+ errorLine1=" final OverlayProperties overlayProperties = defaultDisplay.getOverlaySupport();"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/graphics/java/android/graphics/HardwareRenderer.java"
+ line="1394"
+ column="57"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `isCombinationSupported()` is a flagged API and should be inside an `if (Flags.overlaypropertiesClassApi())` check (or annotate the surrounding method `initDisplayInfo` with `@FlaggedApi(Flags.FLAG_OVERLAYPROPERTIES_CLASS_API) to transfer requirement to caller`)"
+ errorLine1=" overlayProperties.isCombinationSupported("
+ errorLine2=" ^">
+ <location
+ file="frameworks/base/graphics/java/android/graphics/HardwareRenderer.java"
+ line="1422"
+ column="21"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `isCombinationSupported()` is a flagged API and should be inside an `if (Flags.overlaypropertiesClassApi())` check (or annotate the surrounding method `initDisplayInfo` with `@FlaggedApi(Flags.FLAG_OVERLAYPROPERTIES_CLASS_API) to transfer requirement to caller`)"
+ errorLine1=" overlayProperties.isCombinationSupported("
+ errorLine2=" ^">
+ <location
+ file="frameworks/base/graphics/java/android/graphics/HardwareRenderer.java"
+ line="1424"
+ column="21"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `RGBA_10101010` is a flagged API and should be inside an `if (Flags.requestedFormatsV())` check (or annotate the surrounding method `initDisplayInfo` with `@FlaggedApi(Flags.FLAG_REQUESTED_FORMATS_V) to transfer requirement to caller`)"
+ errorLine1=" HardwareBuffer.RGBA_10101010),"
+ errorLine2=" ~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/graphics/java/android/graphics/HardwareRenderer.java"
+ line="1429"
+ column="44"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `isMixedColorSpacesSupported()` is a flagged API and should be inside an `if (Flags.overlaypropertiesClassApi())` check (or annotate the surrounding method `initDisplayInfo` with `@FlaggedApi(Flags.FLAG_OVERLAYPROPERTIES_CLASS_API) to transfer requirement to caller`)"
+ errorLine1=" overlayProperties.isMixedColorSpacesSupported());"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/graphics/java/android/graphics/HardwareRenderer.java"
+ line="1430"
+ column="21"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `CONFIDENCE_LEVEL_VERY_HIGH` is a flagged API and should be inside an `if (Flags.allowHotwordBumpEgress())` check (or annotate the surrounding method `confidenceLevelToString` with `@FlaggedApi(Flags.FLAG_ALLOW_HOTWORD_BUMP_EGRESS) to transfer requirement to caller`)"
+ errorLine1=" case CONFIDENCE_LEVEL_VERY_HIGH:"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/service/voice/HotwordRejectedResult.java"
+ line="120"
+ column="18"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `scheduleMediaViewCleanup()` is a flagged API and should be inside an `if (Flags.enableAdServiceFw())` check (or annotate the surrounding method `release` with `@FlaggedApi(Flags.FLAG_ENABLE_AD_SERVICE_FW) to transfer requirement to caller`)"
+ errorLine1=" mSessionImpl.scheduleMediaViewCleanup();"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/media/java/android/media/tv/ad/ITvAdSessionWrapper.java"
+ line="87"
+ column="9"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `release()` is a flagged API and should be inside an `if (Flags.enableAdServiceFw())` check (or annotate the surrounding method `executeMessage` with `@FlaggedApi(Flags.FLAG_ENABLE_AD_SERVICE_FW) to transfer requirement to caller`)"
+ errorLine1=" mSessionImpl.release();"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/media/java/android/media/tv/ad/ITvAdSessionWrapper.java"
+ line="101"
+ column="17"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `setSurface()` is a flagged API and should be inside an `if (Flags.enableAdServiceFw())` check (or annotate the surrounding method `executeMessage` with `@FlaggedApi(Flags.FLAG_ENABLE_AD_SERVICE_FW) to transfer requirement to caller`)"
+ errorLine1=" mSessionImpl.setSurface((Surface) msg.obj);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/media/java/android/media/tv/ad/ITvAdSessionWrapper.java"
+ line="114"
+ column="17"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `dispatchSurfaceChanged()` is a flagged API and should be inside an `if (Flags.enableAdServiceFw())` check (or annotate the surrounding method `executeMessage` with `@FlaggedApi(Flags.FLAG_ENABLE_AD_SERVICE_FW) to transfer requirement to caller`)"
+ errorLine1=" mSessionImpl.dispatchSurfaceChanged("
+ errorLine2=" ^">
+ <location
+ file="frameworks/base/media/java/android/media/tv/ad/ITvAdSessionWrapper.java"
+ line="119"
+ column="17"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `createMediaView()` is a flagged API and should be inside an `if (Flags.enableAdServiceFw())` check (or annotate the surrounding method `executeMessage` with `@FlaggedApi(Flags.FLAG_ENABLE_AD_SERVICE_FW) to transfer requirement to caller`)"
+ errorLine1=" mSessionImpl.createMediaView((IBinder) args.arg1, (Rect) args.arg2);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/media/java/android/media/tv/ad/ITvAdSessionWrapper.java"
+ line="126"
+ column="17"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `relayoutMediaView()` is a flagged API and should be inside an `if (Flags.enableAdServiceFw())` check (or annotate the surrounding method `executeMessage` with `@FlaggedApi(Flags.FLAG_ENABLE_AD_SERVICE_FW) to transfer requirement to caller`)"
+ errorLine1=" mSessionImpl.relayoutMediaView((Rect) msg.obj);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/media/java/android/media/tv/ad/ITvAdSessionWrapper.java"
+ line="131"
+ column="17"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `removeMediaView()` is a flagged API and should be inside an `if (Flags.enableAdServiceFw())` check (or annotate the surrounding method `executeMessage` with `@FlaggedApi(Flags.FLAG_ENABLE_AD_SERVICE_FW) to transfer requirement to caller`)"
+ errorLine1=" mSessionImpl.removeMediaView(true);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/media/java/android/media/tv/ad/ITvAdSessionWrapper.java"
+ line="135"
+ column="17"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `startAdService()` is a flagged API and should be inside an `if (Flags.enableAdServiceFw())` check (or annotate the surrounding method `executeMessage` with `@FlaggedApi(Flags.FLAG_ENABLE_AD_SERVICE_FW) to transfer requirement to caller`)"
+ errorLine1=" mSessionImpl.startAdService();"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/media/java/android/media/tv/ad/ITvAdSessionWrapper.java"
+ line="139"
+ column="17"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `stopAdService()` is a flagged API and should be inside an `if (Flags.enableAdServiceFw())` check (or annotate the surrounding method `executeMessage` with `@FlaggedApi(Flags.FLAG_ENABLE_AD_SERVICE_FW) to transfer requirement to caller`)"
+ errorLine1=" mSessionImpl.stopAdService();"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/media/java/android/media/tv/ad/ITvAdSessionWrapper.java"
+ line="143"
+ column="17"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `resetAdService()` is a flagged API and should be inside an `if (Flags.enableAdServiceFw())` check (or annotate the surrounding method `executeMessage` with `@FlaggedApi(Flags.FLAG_ENABLE_AD_SERVICE_FW) to transfer requirement to caller`)"
+ errorLine1=" mSessionImpl.resetAdService();"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/media/java/android/media/tv/ad/ITvAdSessionWrapper.java"
+ line="147"
+ column="17"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `sendCurrentVideoBounds()` is a flagged API and should be inside an `if (Flags.enableAdServiceFw())` check (or annotate the surrounding method `executeMessage` with `@FlaggedApi(Flags.FLAG_ENABLE_AD_SERVICE_FW) to transfer requirement to caller`)"
+ errorLine1=" mSessionImpl.sendCurrentVideoBounds((Rect) msg.obj);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/media/java/android/media/tv/ad/ITvAdSessionWrapper.java"
+ line="151"
+ column="17"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `sendCurrentChannelUri()` is a flagged API and should be inside an `if (Flags.enableAdServiceFw())` check (or annotate the surrounding method `executeMessage` with `@FlaggedApi(Flags.FLAG_ENABLE_AD_SERVICE_FW) to transfer requirement to caller`)"
+ errorLine1=" mSessionImpl.sendCurrentChannelUri((Uri) msg.obj);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/media/java/android/media/tv/ad/ITvAdSessionWrapper.java"
+ line="155"
+ column="17"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `sendTrackInfoList()` is a flagged API and should be inside an `if (Flags.enableAdServiceFw())` check (or annotate the surrounding method `executeMessage` with `@FlaggedApi(Flags.FLAG_ENABLE_AD_SERVICE_FW) to transfer requirement to caller`)"
+ errorLine1=" mSessionImpl.sendTrackInfoList((List<TvTrackInfo>) msg.obj);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/media/java/android/media/tv/ad/ITvAdSessionWrapper.java"
+ line="159"
+ column="17"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `sendCurrentTvInputId()` is a flagged API and should be inside an `if (Flags.enableAdServiceFw())` check (or annotate the surrounding method `executeMessage` with `@FlaggedApi(Flags.FLAG_ENABLE_AD_SERVICE_FW) to transfer requirement to caller`)"
+ errorLine1=" mSessionImpl.sendCurrentTvInputId((String) msg.obj);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/media/java/android/media/tv/ad/ITvAdSessionWrapper.java"
+ line="163"
+ column="17"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `sendSigningResult()` is a flagged API and should be inside an `if (Flags.enableAdServiceFw())` check (or annotate the surrounding method `executeMessage` with `@FlaggedApi(Flags.FLAG_ENABLE_AD_SERVICE_FW) to transfer requirement to caller`)"
+ errorLine1=" mSessionImpl.sendSigningResult((String) args.arg1, (byte[]) args.arg2);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/media/java/android/media/tv/ad/ITvAdSessionWrapper.java"
+ line="168"
+ column="17"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `notifyError()` is a flagged API and should be inside an `if (Flags.enableAdServiceFw())` check (or annotate the surrounding method `executeMessage` with `@FlaggedApi(Flags.FLAG_ENABLE_AD_SERVICE_FW) to transfer requirement to caller`)"
+ errorLine1=" mSessionImpl.notifyError((String) args.arg1, (Bundle) args.arg2);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/media/java/android/media/tv/ad/ITvAdSessionWrapper.java"
+ line="174"
+ column="17"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `notifyTvMessage()` is a flagged API and should be inside an `if (Flags.enableAdServiceFw())` check (or annotate the surrounding method `executeMessage` with `@FlaggedApi(Flags.FLAG_ENABLE_AD_SERVICE_FW) to transfer requirement to caller`)"
+ errorLine1=" mSessionImpl.notifyTvMessage((Integer) args.arg1, (Bundle) args.arg2);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/media/java/android/media/tv/ad/ITvAdSessionWrapper.java"
+ line="180"
+ column="17"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `notifyTvInputSessionData()` is a flagged API and should be inside an `if (Flags.enableAdServiceFw())` check (or annotate the surrounding method `executeMessage` with `@FlaggedApi(Flags.FLAG_ENABLE_AD_SERVICE_FW) to transfer requirement to caller`)"
+ errorLine1=" mSessionImpl.notifyTvInputSessionData((String) args.arg1, (Bundle) args.arg2);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/media/java/android/media/tv/ad/ITvAdSessionWrapper.java"
+ line="186"
+ column="17"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `dispatchInputEvent()` is a flagged API and should be inside an `if (Flags.enableAdServiceFw())` check (or annotate the surrounding method `onInputEvent` with `@FlaggedApi(Flags.FLAG_ENABLE_AD_SERVICE_FW) to transfer requirement to caller`)"
+ errorLine1=" int handled = mSessionImpl.dispatchInputEvent(event, this);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/media/java/android/media/tv/ad/ITvAdSessionWrapper.java"
+ line="309"
+ column="27"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `DISPATCH_IN_PROGRESS` is a flagged API and should be inside an `if (Flags.enableAdServiceFw())` check (or annotate the surrounding method `onInputEvent` with `@FlaggedApi(Flags.FLAG_ENABLE_AD_SERVICE_FW) to transfer requirement to caller`)"
+ errorLine1=" if (handled != TvAdManager.Session.DISPATCH_IN_PROGRESS) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/media/java/android/media/tv/ad/ITvAdSessionWrapper.java"
+ line="310"
+ column="48"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `DISPATCH_HANDLED` is a flagged API and should be inside an `if (Flags.enableAdServiceFw())` check (or annotate the surrounding method `onInputEvent` with `@FlaggedApi(Flags.FLAG_ENABLE_AD_SERVICE_FW) to transfer requirement to caller`)"
+ errorLine1=" event, handled == TvAdManager.Session.DISPATCH_HANDLED);"
+ errorLine2=" ~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/media/java/android/media/tv/ad/ITvAdSessionWrapper.java"
+ line="312"
+ column="63"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `onDeregistered()` is a flagged API and should be inside an `if (Flags.emergencyRegistrationState())` check (or annotate the surrounding method `onDeregistered` with `@FlaggedApi(Flags.FLAG_EMERGENCY_REGISTRATION_STATE) to transfer requirement to caller`)"
+ errorLine1=" onDeregistered(info, suggestedAction, attributes);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java"
+ line="576"
+ column="9"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `onTechnologyChangeFailed()` is a flagged API and should be inside an `if (Flags.emergencyRegistrationState())` check (or annotate the surrounding method `onTechnologyChangeFailed` with `@FlaggedApi(Flags.FLAG_EMERGENCY_REGISTRATION_STATE) to transfer requirement to caller`)"
+ errorLine1=" onTechnologyChangeFailed(info, attributes);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java"
+ line="703"
+ column="9"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `ATTR_REGISTRATION_TYPE_EMERGENCY` is a flagged API and should be inside an `if (Flags.emergencyRegistrationState())` check (or annotate the surrounding method `isEmergency` with `@FlaggedApi(Flags.FLAG_EMERGENCY_REGISTRATION_STATE) to transfer requirement to caller`)"
+ errorLine1=" & ImsRegistrationAttributes.ATTR_REGISTRATION_TYPE_EMERGENCY) != 0;"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java"
+ line="753"
+ column="49"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `CAPABILITY_SUPPORTS_SIMULTANEOUS_CALLING` is a flagged API and should be inside an `if (Flags.simultaneousCallingIndications())` check (or annotate the surrounding method `?` with `@FlaggedApi(Flags.FLAG_SIMULTANEOUS_CALLING_INDICATIONS) to transfer requirement to caller`)"
+ errorLine1=" Long.numberOfTrailingZeros(CAPABILITY_SUPPORTS_SIMULTANEOUS_CALLING);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/ims/ImsService.java"
+ line="186"
+ column="40"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `CAPABILITY_SUPPORTS_SIMULTANEOUS_CALLING` is a flagged API and should be inside an `if (Flags.simultaneousCallingIndications())` check (or annotate the surrounding method `?` with `@FlaggedApi(Flags.FLAG_SIMULTANEOUS_CALLING_INDICATIONS) to transfer requirement to caller`)"
+ errorLine1=" CAPABILITY_SUPPORTS_SIMULTANEOUS_CALLING, "SIMULTANEOUS_CALLING");"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/ims/ImsService.java"
+ line="212"
+ column="13"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `InputTransferToken()` is a flagged API and should be inside an `if (Flags.surfaceControlInputReceiver())` check (or annotate the surrounding method `handleRenderSuggestion` with `@FlaggedApi(Flags.FLAG_SURFACE_CONTROL_INPUT_RECEIVER) to transfer requirement to caller`)"
+ errorLine1=" new InputTransferToken(hostInputToken), "InlineSuggestionRenderService");"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/service/autofill/InlineSuggestionRenderService.java"
+ line="170"
+ column="21"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `ViewBehavior()` is a flagged API and should be inside an `if (Flags.inputDeviceViewBehaviorApi())` check (or annotate the surrounding method `?` with `@FlaggedApi(Flags.FLAG_INPUT_DEVICE_VIEW_BEHAVIOR_API) to transfer requirement to caller`)"
+ errorLine1=" private final ViewBehavior mViewBehavior = new ViewBehavior(this);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/view/InputDevice.java"
+ line="99"
+ column="48"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `mShouldSmoothScroll` is a flagged API and should be inside an `if (Flags.inputDeviceViewBehaviorApi())` check (or annotate the surrounding method `InputDevice` with `@FlaggedApi(Flags.FLAG_INPUT_DEVICE_VIEW_BEHAVIOR_API) to transfer requirement to caller`)"
+ errorLine1=" mViewBehavior.mShouldSmoothScroll = in.readBoolean();"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/view/InputDevice.java"
+ line="575"
+ column="23"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `mShouldSmoothScroll` is a flagged API and should be inside an `if (Flags.inputDeviceViewBehaviorApi())` check (or annotate the surrounding method `setShouldSmoothScroll` with `@FlaggedApi(Flags.FLAG_INPUT_DEVICE_VIEW_BEHAVIOR_API) to transfer requirement to caller`)"
+ errorLine1=" mViewBehavior.mShouldSmoothScroll = shouldSmoothScroll;"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/view/InputDevice.java"
+ line="1207"
+ column="23"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `mShouldSmoothScroll` is a flagged API and should be inside an `if (Flags.inputDeviceViewBehaviorApi())` check (or annotate the surrounding method `writeToParcel` with `@FlaggedApi(Flags.FLAG_INPUT_DEVICE_VIEW_BEHAVIOR_API) to transfer requirement to caller`)"
+ errorLine1=" out.writeBoolean(mViewBehavior.mShouldSmoothScroll);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/view/InputDevice.java"
+ line="1642"
+ column="40"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `getHandwritingDelegateFlags()` is a flagged API and should be inside an `if (Flags.homeScreenHandwritingDelegator())` check (or annotate the surrounding method `acceptStylusHandwritingDelegation` with `@FlaggedApi(Flags.FLAG_HOME_SCREEN_HANDWRITING_DELEGATOR) to transfer requirement to caller`)"
+ errorLine1=" delegateView.getHandwritingDelegateFlags());"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/view/inputmethod/InputMethodManager.java"
+ line="2880"
+ column="17"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `getHandwritingDelegateFlags()` is a flagged API and should be inside an `if (Flags.homeScreenHandwritingDelegator())` check (or annotate the surrounding method `acceptStylusHandwritingDelegation` with `@FlaggedApi(Flags.FLAG_HOME_SCREEN_HANDWRITING_DELEGATOR) to transfer requirement to caller`)"
+ errorLine1=" delegateView, delegatorPackageName, delegateView.getHandwritingDelegateFlags());"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/view/inputmethod/InputMethodManager.java"
+ line="2911"
+ column="53"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `acceptStylusHandwritingDelegation()` is a flagged API and should be inside an `if (Flags.homeScreenHandwritingDelegator())` check (or annotate the surrounding method `acceptStylusHandwritingDelegation` with `@FlaggedApi(Flags.FLAG_HOME_SCREEN_HANDWRITING_DELEGATOR) to transfer requirement to caller`)"
+ errorLine1=" acceptStylusHandwritingDelegation("
+ errorLine2=" ^">
+ <location
+ file="frameworks/base/core/java/android/view/inputmethod/InputMethodManager.java"
+ line="2940"
+ column="9"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `onError()` is a flagged API and should be inside an `if (Flags.connectionlessHandwriting())` check (or annotate the surrounding method `onResult` with `@FlaggedApi(Flags.FLAG_CONNECTIONLESS_HANDWRITING) to transfer requirement to caller`)"
+ errorLine1=" executor.execute(() -> callback.onError("
+ errorLine2=" ^">
+ <location
+ file="frameworks/base/core/java/android/view/inputmethod/InputMethodManager.java"
+ line="4808"
+ column="44"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `CONNECTIONLESS_HANDWRITING_ERROR_NO_TEXT_RECOGNIZED` is a flagged API and should be inside an `if (Flags.connectionlessHandwriting())` check (or annotate the surrounding method `onResult` with `@FlaggedApi(Flags.FLAG_CONNECTIONLESS_HANDWRITING) to transfer requirement to caller`)"
+ errorLine1=" .CONNECTIONLESS_HANDWRITING_ERROR_NO_TEXT_RECOGNIZED));"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/view/inputmethod/InputMethodManager.java"
+ line="4810"
+ column="38"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `onResult()` is a flagged API and should be inside an `if (Flags.connectionlessHandwriting())` check (or annotate the surrounding method `onResult` with `@FlaggedApi(Flags.FLAG_CONNECTIONLESS_HANDWRITING) to transfer requirement to caller`)"
+ errorLine1=" executor.execute(() -> callback.onResult(text));"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/view/inputmethod/InputMethodManager.java"
+ line="4812"
+ column="44"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `onError()` is a flagged API and should be inside an `if (Flags.connectionlessHandwriting())` check (or annotate the surrounding method `onError` with `@FlaggedApi(Flags.FLAG_CONNECTIONLESS_HANDWRITING) to transfer requirement to caller`)"
+ errorLine1=" executor.execute(() -> callback.onError(errorCode));"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/view/inputmethod/InputMethodManager.java"
+ line="4834"
+ column="40"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `onStartConnectionlessStylusHandwriting()` is a flagged API and should be inside an `if (Flags.connectionlessHandwriting())` check (or annotate the surrounding method `canStartStylusHandwriting` with `@FlaggedApi(Flags.FLAG_CONNECTIONLESS_HANDWRITING) to transfer requirement to caller`)"
+ errorLine1=" if (onStartConnectionlessStylusHandwriting("
+ errorLine2=" ^">
+ <location
+ file="frameworks/base/core/java/android/inputmethodservice/InputMethodService.java"
+ line="1085"
+ column="21"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `CONNECTIONLESS_HANDWRITING_ERROR_UNSUPPORTED` is a flagged API and should be inside an `if (Flags.connectionlessHandwriting())` check (or annotate the surrounding method `canStartStylusHandwriting` with `@FlaggedApi(Flags.FLAG_CONNECTIONLESS_HANDWRITING) to transfer requirement to caller`)"
+ errorLine1=" CONNECTIONLESS_HANDWRITING_ERROR_UNSUPPORTED);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/inputmethodservice/InputMethodService.java"
+ line="1096"
+ column="33"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `CONNECTIONLESS_HANDWRITING_ERROR_OTHER` is a flagged API and should be inside an `if (Flags.connectionlessHandwriting())` check (or annotate the surrounding method `finishStylusHandwriting` with `@FlaggedApi(Flags.FLAG_CONNECTIONLESS_HANDWRITING) to transfer requirement to caller`)"
+ errorLine1=" mConnectionlessHandwritingCallback.onError(CONNECTIONLESS_HANDWRITING_ERROR_OTHER);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/inputmethodservice/InputMethodService.java"
+ line="2825"
+ column="60"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `getAccessibilityBounceKeysThreshold()` is a flagged API and should be inside an `if (Flags.keyboardA11yBounceKeysFlag())` check (or annotate the surrounding method `isAccessibilityBounceKeysEnabled` with `@FlaggedApi(Flags.FLAG_KEYBOARD_A11Y_BOUNCE_KEYS_FLAG) to transfer requirement to caller`)"
+ errorLine1=" return getAccessibilityBounceKeysThreshold(context) != 0;"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/hardware/input/InputSettings.java"
+ line="458"
+ column="16"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `getAccessibilitySlowKeysThreshold()` is a flagged API and should be inside an `if (Flags.keyboardA11ySlowKeysFlag())` check (or annotate the surrounding method `isAccessibilitySlowKeysEnabled` with `@FlaggedApi(Flags.FLAG_KEYBOARD_A11Y_SLOW_KEYS_FLAG) to transfer requirement to caller`)"
+ errorLine1=" return getAccessibilitySlowKeysThreshold(context) != 0;"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/hardware/input/InputSettings.java"
+ line="542"
+ column="16"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `APPEARANCE_TRANSPARENT_CAPTION_BAR_BACKGROUND` is a flagged API and should be inside an `if (Flags.customizableWindowHeaders())` check (or annotate the surrounding method `?` with `@FlaggedApi(Flags.FLAG_CUSTOMIZABLE_WINDOW_HEADERS) to transfer requirement to caller`)"
+ errorLine1=" mask = APPEARANCE_TRANSPARENT_CAPTION_BAR_BACKGROUND,"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/view/InsetsFlags.java"
+ line="76"
+ column="28"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `APPEARANCE_TRANSPARENT_CAPTION_BAR_BACKGROUND` is a flagged API and should be inside an `if (Flags.customizableWindowHeaders())` check (or annotate the surrounding method `?` with `@FlaggedApi(Flags.FLAG_CUSTOMIZABLE_WINDOW_HEADERS) to transfer requirement to caller`)"
+ errorLine1=" equals = APPEARANCE_TRANSPARENT_CAPTION_BAR_BACKGROUND,"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/view/InsetsFlags.java"
+ line="77"
+ column="30"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `APPEARANCE_LIGHT_CAPTION_BARS` is a flagged API and should be inside an `if (Flags.customizableWindowHeaders())` check (or annotate the surrounding method `?` with `@FlaggedApi(Flags.FLAG_CUSTOMIZABLE_WINDOW_HEADERS) to transfer requirement to caller`)"
+ errorLine1=" mask = APPEARANCE_LIGHT_CAPTION_BARS,"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/view/InsetsFlags.java"
+ line="80"
+ column="28"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `APPEARANCE_LIGHT_CAPTION_BARS` is a flagged API and should be inside an `if (Flags.customizableWindowHeaders())` check (or annotate the surrounding method `?` with `@FlaggedApi(Flags.FLAG_CUSTOMIZABLE_WINDOW_HEADERS) to transfer requirement to caller`)"
+ errorLine1=" equals = APPEARANCE_LIGHT_CAPTION_BARS,"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/view/InsetsFlags.java"
+ line="81"
+ column="30"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `countUriRelativeFilterGroups()` is a flagged API and should be inside an `if (Flags.relativeReferenceIntentFilters())` check (or annotate the surrounding method `toLongString` with `@FlaggedApi(Flags.FLAG_RELATIVE_REFERENCE_INTENT_FILTERS) to transfer requirement to caller`)"
+ errorLine1=" if (Flags.relativeReferenceIntentFilters() && countUriRelativeFilterGroups() > 0) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/content/IntentFilter.java"
+ line="577"
+ column="55"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `matchGroupsToUri()` is a flagged API and should be inside an `if (Flags.relativeReferenceIntentFilters())` check (or annotate the surrounding method `matchRelRefGroups` with `@FlaggedApi(Flags.FLAG_RELATIVE_REFERENCE_INTENT_FILTERS) to transfer requirement to caller`)"
+ errorLine1=" return UriRelativeFilterGroup.matchGroupsToUri(mUriRelativeFilterGroups, data);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/content/IntentFilter.java"
+ line="1839"
+ column="16"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `isPrivateProfile()` is a flagged API and should be inside an `if (Flags.allowPrivateProfile())` check (or annotate the surrounding method `getPrivateProfile` with `@FlaggedApi(Flags.FLAG_ALLOW_PRIVATE_PROFILE) to transfer requirement to caller`)"
+ errorLine1=" if (userInfo.isPrivateProfile()) return userInfo;"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/com/android/internal/app/IntentForwarderActivity.java"
+ line="631"
+ column="17"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `uptimeNanos()` is a flagged API and should be inside an `if (Flags.adpfGpuReportActualWorkDuration())` check (or annotate the surrounding method `postEventLogToWorkerThread` with `@FlaggedApi(Flags.FLAG_ADPF_GPU_REPORT_ACTUAL_WORK_DURATION) to transfer requirement to caller`)"
+ errorLine1=" final long realtimeNanos = SystemClock.uptimeNanos();"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/com/android/internal/jank/InteractionJankMonitor.java"
+ line="606"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `KEYCODE_SCREENSHOT` is a flagged API and should be inside an `if (Flags.emojiAndScreenshotKeycodesAvailable())` check (or annotate the surrounding method `?` with `@FlaggedApi(Flags.FLAG_EMOJI_AND_SCREENSHOT_KEYCODES_AVAILABLE) to transfer requirement to caller`)"
+ errorLine1=" public static final int LAST_KEYCODE = KEYCODE_SCREENSHOT;"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/view/KeyEvent.java"
+ line="955"
+ column="44"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `isMgf1DigestsSpecified()` is a flagged API and should be inside an `if (Flags.mgf1DigestSetterV2())` check (or annotate the surrounding method `Builder` with `@FlaggedApi(Flags.FLAG_MGF1_DIGEST_SETTER_V2) to transfer requirement to caller`)"
+ errorLine1=" if (sourceSpec.isMgf1DigestsSpecified()) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/keystore/java/android/security/keystore/KeyGenParameterSpec.java"
+ line="1025"
+ column="17"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `getMgf1Digests()` is a flagged API and should be inside an `if (Flags.mgf1DigestSetterV2())` check (or annotate the surrounding method `Builder` with `@FlaggedApi(Flags.FLAG_MGF1_DIGEST_SETTER_V2) to transfer requirement to caller`)"
+ errorLine1=" mMgf1Digests = sourceSpec.getMgf1Digests();"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/keystore/java/android/security/keystore/KeyGenParameterSpec.java"
+ line="1026"
+ column="32"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `BIOMETRIC_NO_AUTHENTICATION` is a flagged API and should be inside an `if (Flags.lastAuthenticationTime())` check (or annotate the surrounding method `getLastAuthTime` with `@FlaggedApi(Flags.FLAG_LAST_AUTHENTICATION_TIME) to transfer requirement to caller`)"
+ errorLine1=" return BiometricConstants.BIOMETRIC_NO_AUTHENTICATION;"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/keystore/java/android/security/KeyStoreAuthorization.java"
+ line="139"
+ column="39"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `BIOMETRIC_NO_AUTHENTICATION` is a flagged API and should be inside an `if (Flags.lastAuthenticationTime())` check (or annotate the surrounding method `getLastAuthTime` with `@FlaggedApi(Flags.FLAG_LAST_AUTHENTICATION_TIME) to transfer requirement to caller`)"
+ errorLine1=" return BiometricConstants.BIOMETRIC_NO_AUTHENTICATION;"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/keystore/java/android/security/KeyStoreAuthorization.java"
+ line="145"
+ column="39"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `PERSISTENT_DATA_BLOCK_SERVICE` is a flagged API and should be inside an `if (Flags.frpEnforcement())` check (or annotate the surrounding method `createConfirmFactoryResetCredentialIntent` with `@FlaggedApi(Flags.FLAG_FRP_ENFORCEMENT) to transfer requirement to caller`)"
+ errorLine1=" ServiceManager.getService(Context.PERSISTENT_DATA_BLOCK_SERVICE));"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/app/KeyguardManager.java"
+ line="365"
+ column="55"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `isPrivateProfile()` is a flagged API and should be inside an `if (Flags.allowPrivateProfile())` check (or annotate the surrounding method `getProfiles` with `@FlaggedApi(Flags.FLAG_ALLOW_PRIVATE_PROFILE) to transfer requirement to caller`)"
+ errorLine1=" && mUserManager.isPrivateProfile())) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/content/pm/LauncherApps.java"
+ line="712"
+ column="24"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `computeDrawingBoundingBox()` is a flagged API and should be inside an `if (Flags.useBoundsForWidth())` check (or annotate the surrounding method `draw` with `@FlaggedApi(Flags.FLAG_USE_BOUNDS_FOR_WIDTH) to transfer requirement to caller`)"
+ errorLine1=" RectF drawingRect = computeDrawingBoundingBox();"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/text/Layout.java"
+ line="498"
+ column="33"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `getLineSpacingMultiplier()` is a flagged API and should be inside an `if (Flags.useBoundsForWidth())` check (or annotate the surrounding method `getSpacingMultiplier` with `@FlaggedApi(Flags.FLAG_USE_BOUNDS_FOR_WIDTH) to transfer requirement to caller`)"
+ errorLine1=" return getLineSpacingMultiplier();"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/text/Layout.java"
+ line="4341"
+ column="16"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `getLineSpacingAmount()` is a flagged API and should be inside an `if (Flags.useBoundsForWidth())` check (or annotate the surrounding method `getSpacingAdd` with `@FlaggedApi(Flags.FLAG_USE_BOUNDS_FOR_WIDTH) to transfer requirement to caller`)"
+ errorLine1=" return getLineSpacingAmount();"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/text/Layout.java"
+ line="4368"
+ column="16"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `LINE_BREAK_STYLE_UNSPECIFIED` is a flagged API and should be inside an `if (Flags.noBreakNoHyphenationSpan())` check (or annotate the surrounding method `?` with `@FlaggedApi(Flags.FLAG_NO_BREAK_NO_HYPHENATION_SPAN) to transfer requirement to caller`)"
+ errorLine1=" private @LineBreakStyle int mLineBreakStyle = LineBreakConfig.LINE_BREAK_STYLE_UNSPECIFIED;"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/graphics/java/android/graphics/text/LineBreakConfig.java"
+ line="276"
+ column="71"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `LINE_BREAK_WORD_STYLE_UNSPECIFIED` is a flagged API and should be inside an `if (Flags.noBreakNoHyphenationSpan())` check (or annotate the surrounding method `?` with `@FlaggedApi(Flags.FLAG_NO_BREAK_NO_HYPHENATION_SPAN) to transfer requirement to caller`)"
+ errorLine1=" LineBreakConfig.LINE_BREAK_WORD_STYLE_UNSPECIFIED;"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/graphics/java/android/graphics/text/LineBreakConfig.java"
+ line="280"
+ column="33"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `HYPHENATION_UNSPECIFIED` is a flagged API and should be inside an `if (Flags.noBreakNoHyphenationSpan())` check (or annotate the surrounding method `?` with `@FlaggedApi(Flags.FLAG_NO_BREAK_NO_HYPHENATION_SPAN) to transfer requirement to caller`)"
+ errorLine1=" private @Hyphenation int mHyphenation = LineBreakConfig.HYPHENATION_UNSPECIFIED;"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/graphics/java/android/graphics/text/LineBreakConfig.java"
+ line="282"
+ column="65"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `LINE_BREAK_STYLE_UNSPECIFIED` is a flagged API and should be inside an `if (Flags.noBreakNoHyphenationSpan())` check (or annotate the surrounding method `reset` with `@FlaggedApi(Flags.FLAG_NO_BREAK_NO_HYPHENATION_SPAN) to transfer requirement to caller`)"
+ errorLine1=" mLineBreakStyle = LINE_BREAK_STYLE_UNSPECIFIED;"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/graphics/java/android/graphics/text/LineBreakConfig.java"
+ line="343"
+ column="35"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `LINE_BREAK_WORD_STYLE_UNSPECIFIED` is a flagged API and should be inside an `if (Flags.noBreakNoHyphenationSpan())` check (or annotate the surrounding method `reset` with `@FlaggedApi(Flags.FLAG_NO_BREAK_NO_HYPHENATION_SPAN) to transfer requirement to caller`)"
+ errorLine1=" mLineBreakWordStyle = LINE_BREAK_WORD_STYLE_UNSPECIFIED;"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/graphics/java/android/graphics/text/LineBreakConfig.java"
+ line="344"
+ column="39"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `HYPHENATION_UNSPECIFIED` is a flagged API and should be inside an `if (Flags.noBreakNoHyphenationSpan())` check (or annotate the surrounding method `reset` with `@FlaggedApi(Flags.FLAG_NO_BREAK_NO_HYPHENATION_SPAN) to transfer requirement to caller`)"
+ errorLine1=" mHyphenation = HYPHENATION_UNSPECIFIED;"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/graphics/java/android/graphics/text/LineBreakConfig.java"
+ line="345"
+ column="32"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `LINE_BREAK_STYLE_AUTO` is a flagged API and should be inside an `if (Flags.wordStyleAuto())` check (or annotate the surrounding method `getResolvedLineBreakStyle` with `@FlaggedApi(Flags.FLAG_WORD_STYLE_AUTO) to transfer requirement to caller`)"
+ errorLine1=" defaultStyle = LINE_BREAK_STYLE_AUTO;"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/graphics/java/android/graphics/text/LineBreakConfig.java"
+ line="492"
+ column="28"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `LINE_BREAK_STYLE_UNSPECIFIED` is a flagged API and should be inside an `if (Flags.noBreakNoHyphenationSpan())` check (or annotate the surrounding method `getResolvedLineBreakStyle` with `@FlaggedApi(Flags.FLAG_NO_BREAK_NO_HYPHENATION_SPAN) to transfer requirement to caller`)"
+ errorLine1=" return config.mLineBreakStyle == LINE_BREAK_STYLE_UNSPECIFIED"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/graphics/java/android/graphics/text/LineBreakConfig.java"
+ line="499"
+ column="42"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `LINE_BREAK_WORD_STYLE_AUTO` is a flagged API and should be inside an `if (Flags.wordStyleAuto())` check (or annotate the surrounding method `getResolvedLineBreakWordStyle` with `@FlaggedApi(Flags.FLAG_WORD_STYLE_AUTO) to transfer requirement to caller`)"
+ errorLine1=" defaultWordStyle = LINE_BREAK_WORD_STYLE_AUTO;"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/graphics/java/android/graphics/text/LineBreakConfig.java"
+ line="527"
+ column="32"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `LINE_BREAK_WORD_STYLE_UNSPECIFIED` is a flagged API and should be inside an `if (Flags.noBreakNoHyphenationSpan())` check (or annotate the surrounding method `getResolvedLineBreakWordStyle` with `@FlaggedApi(Flags.FLAG_NO_BREAK_NO_HYPHENATION_SPAN) to transfer requirement to caller`)"
+ errorLine1=" return config.mLineBreakWordStyle == LINE_BREAK_WORD_STYLE_UNSPECIFIED"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/graphics/java/android/graphics/text/LineBreakConfig.java"
+ line="534"
+ column="46"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `HYPHENATION_ENABLED` is a flagged API and should be inside an `if (Flags.noBreakNoHyphenationSpan())` check (or annotate the surrounding method `getResolvedHyphenation` with `@FlaggedApi(Flags.FLAG_NO_BREAK_NO_HYPHENATION_SPAN) to transfer requirement to caller`)"
+ errorLine1=" return HYPHENATION_ENABLED;"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/graphics/java/android/graphics/text/LineBreakConfig.java"
+ line="559"
+ column="20"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `HYPHENATION_UNSPECIFIED` is a flagged API and should be inside an `if (Flags.noBreakNoHyphenationSpan())` check (or annotate the surrounding method `getResolvedHyphenation` with `@FlaggedApi(Flags.FLAG_NO_BREAK_NO_HYPHENATION_SPAN) to transfer requirement to caller`)"
+ errorLine1=" return config.mHyphenation == HYPHENATION_UNSPECIFIED"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/graphics/java/android/graphics/text/LineBreakConfig.java"
+ line="561"
+ column="39"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `HYPHENATION_ENABLED` is a flagged API and should be inside an `if (Flags.noBreakNoHyphenationSpan())` check (or annotate the surrounding method `getResolvedHyphenation` with `@FlaggedApi(Flags.FLAG_NO_BREAK_NO_HYPHENATION_SPAN) to transfer requirement to caller`)"
+ errorLine1=" ? HYPHENATION_ENABLED : config.mHyphenation;"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/graphics/java/android/graphics/text/LineBreakConfig.java"
+ line="562"
+ column="19"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `getSessionId()` is a flagged API and should be inside an `if (Flags.loudnessConfiguratorApi())` check (or annotate the surrounding method `dispatchLoudnessCodecParameterChange` with `@FlaggedApi(Flags.FLAG_LOUDNESS_CONFIGURATOR_API) to transfer requirement to caller`)"
+ errorLine1=" if (lcConfig.getSessionId() == sessionId) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/media/java/android/media/LoudnessCodecDispatcher.java"
+ line="85"
+ column="29"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `mediaCodecsConsume()` is a flagged API and should be inside an `if (Flags.loudnessConfiguratorApi())` check (or annotate the surrounding method `dispatchLoudnessCodecParameterChange` with `@FlaggedApi(Flags.FLAG_LOUDNESS_CONFIGURATOR_API) to transfer requirement to caller`)"
+ errorLine1=" lcConfig.mediaCodecsConsume(mcEntry -> {"
+ errorLine2=" ^">
+ <location
+ file="frameworks/base/media/java/android/media/LoudnessCodecDispatcher.java"
+ line="86"
+ column="29"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `onLoudnessCodecUpdate()` is a flagged API and should be inside an `if (Flags.loudnessConfiguratorApi())` check (or annotate the surrounding method `dispatchLoudnessCodecParameterChange` with `@FlaggedApi(Flags.FLAG_LOUDNESS_CONFIGURATOR_API) to transfer requirement to caller`)"
+ errorLine1=" l.onLoudnessCodecUpdate(mediaCodec,"
+ errorLine2=" ^">
+ <location
+ file="frameworks/base/media/java/android/media/LoudnessCodecDispatcher.java"
+ line="110"
+ column="53"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.provider.user_keys")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="29"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.provider.user_keys")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="29"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.provider.user_keys")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="29"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.provider.user_keys")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="29"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("com.android.internal.camera.flags.camera_hsum_permission")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="552"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("com.android.internal.camera.flags.camera_privacy_allowlist")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="561"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("com.android.net.thread.platform.flags.thread_enabled_platform")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="992"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.net.platform.flags.register_nsd_offload_engine")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="1055"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.content.pm.quarantined_enabled")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="1101"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.content.pm.quarantined_enabled")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="1101"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("com.android.window.flags.screen_recording_callbacks")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="1310"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("com.android.window.flags.screen_recording_callbacks")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="1310"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("com.android.window.flags.screen_recording_callbacks")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="1310"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("com.android.window.flags.screen_recording_callbacks")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="1310"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("com.android.window.flags.screen_recording_callbacks")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="1310"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.security.frp_enforcement")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="1434"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.security.frp_enforcement")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="1434"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("com.android.internal.telephony.flags.use_oem_domain_selection_service")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="1639"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("com.android.server.telecom.flags.telecom_resolve_hidden_dependencies")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="1726"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("com.android.server.telecom.flags.telecom_resolve_hidden_dependencies")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="1726"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("com.android.server.telecom.flags.telecom_resolve_hidden_dependencies")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="1726"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("com.android.server.telecom.flags.telecom_resolve_hidden_dependencies")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="1726"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.multiuser.enable_permission_to_access_hidden_profiles")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="1839"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.multiuser.enable_permission_to_access_hidden_profiles")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="1839"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.multiuser.enable_permission_to_access_hidden_profiles")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="1839"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.multiuser.enable_permission_to_access_hidden_profiles")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="1839"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.multiuser.enable_permission_to_access_hidden_profiles")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="1839"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.multiuser.enable_permission_to_access_hidden_profiles")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="1839"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.multiuser.enable_permission_to_access_hidden_profiles")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="1839"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.multiuser.enable_permission_to_access_hidden_profiles")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="1839"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.multiuser.enable_permission_to_access_hidden_profiles")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="1839"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.multiuser.enable_permission_to_access_hidden_profiles")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="1839"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.multiuser.enable_permission_to_access_hidden_profiles")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="1839"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.multiuser.enable_permission_to_access_hidden_profiles")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="1839"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.multiuser.enable_permission_to_access_hidden_profiles")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="1839"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.multiuser.enable_permission_to_access_hidden_profiles")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="1839"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.multiuser.enable_permission_to_access_hidden_profiles")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="1839"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.multiuser.enable_permission_to_access_hidden_profiles")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="1839"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.multiuser.enable_permission_to_access_hidden_profiles")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="1839"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.multiuser.enable_permission_to_access_hidden_profiles")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="1839"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.multiuser.enable_permission_to_access_hidden_profiles")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="1848"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.multiuser.enable_permission_to_access_hidden_profiles")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="1848"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.multiuser.enable_permission_to_access_hidden_profiles")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="1848"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.multiuser.enable_permission_to_access_hidden_profiles")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="1848"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.multiuser.enable_permission_to_access_hidden_profiles")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="1848"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.multiuser.enable_permission_to_access_hidden_profiles")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="1848"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.multiuser.enable_permission_to_access_hidden_profiles")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="1848"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.multiuser.enable_permission_to_access_hidden_profiles")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="1848"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.multiuser.enable_permission_to_access_hidden_profiles")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="1848"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.multiuser.enable_permission_to_access_hidden_profiles")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="1848"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.multiuser.enable_permission_to_access_hidden_profiles")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="1848"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.multiuser.enable_permission_to_access_hidden_profiles")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="1848"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.multiuser.enable_permission_to_access_hidden_profiles")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="1848"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.multiuser.enable_permission_to_access_hidden_profiles")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="1848"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.multiuser.enable_permission_to_access_hidden_profiles")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="1848"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.multiuser.enable_permission_to_access_hidden_profiles")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="1848"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.multiuser.enable_permission_to_access_hidden_profiles")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="1848"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.multiuser.enable_permission_to_access_hidden_profiles")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="1848"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("com.android.net.thread.platform.flags.thread_user_restriction_enabled")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="2292"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.app.admin.flags.assist_content_user_restriction_enabled")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="2300"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.app.admin.flags.security_log_v2_enabled")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="2363"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.app.admin.flags.security_log_v2_enabled")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="2363"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.app.admin.flags.security_log_v2_enabled")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="2363"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.app.admin.flags.security_log_v2_enabled")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="2363"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.app.admin.flags.security_log_v2_enabled")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="2363"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.app.admin.flags.device_theft_api_enabled")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="2489"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.app.admin.flags.device_theft_api_enabled")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="2489"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.view.contentprotection.flags.manage_device_policy_enabled")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="2523"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.view.contentprotection.flags.manage_device_policy_enabled")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="2523"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.view.contentprotection.flags.manage_device_policy_enabled")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="2523"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.app.admin.flags.esim_management_enabled")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="2532"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.app.admin.flags.esim_management_enabled")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="2532"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.app.admin.flags.esim_management_enabled")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="2532"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.app.admin.flags.esim_management_enabled")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="2532"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.app.admin.flags.dedicated_device_control_api_enabled")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="2539"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.app.admin.flags.dedicated_device_control_api_enabled")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="2546"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.app.admin.flags.dedicated_device_control_api_enabled")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="2553"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.permission.flags.enhanced_confirmation_mode_apis_enabled")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="2596"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.permission.flags.enhanced_confirmation_mode_apis_enabled")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="2596"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.permission.flags.enhanced_confirmation_mode_apis_enabled")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="2596"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("com.android.window.flags.untrusted_embedding_any_app_permission")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="2661"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("com.android.window.flags.always_update_wallpaper_permission")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="2904"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("com.android.window.flags.always_update_wallpaper_permission")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="2904"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("com.android.server.feature.flags.enable_read_dropbox_permission")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="3364"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("com.android.server.feature.flags.enable_read_dropbox_permission")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="3364"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("com.android.server.feature.flags.enable_read_dropbox_permission")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="3364"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("com.android.server.accessibility.motion_event_observing")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="3584"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.media.tv.flags.enable_ad_service_fw")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="3971"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.content.pm.get_resolved_apk_path")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="4252"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.content.pm.get_resolved_apk_path")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="4252"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.companion.device_presence")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="4465"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.companion.device_presence")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="4465"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.companion.flags.companion_transport_apis")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="4475"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.companion.flags.companion_transport_apis")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="4475"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.companion.flags.companion_transport_apis")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="4475"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.companion.flags.companion_transport_apis")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="4475"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.companion.flags.companion_transport_apis")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="4475"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.companion.flags.companion_transport_apis")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="4475"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("com.android.media.flags.enable_privileged_routing_for_media_routing_control")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="4780"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("com.android.media.flags.enable_privileged_routing_for_media_routing_control")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="4780"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("com.android.media.flags.enable_privileged_routing_for_media_routing_control")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="4780"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("com.android.media.flags.enable_privileged_routing_for_media_routing_control")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="4780"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("com.android.media.flags.enable_privileged_routing_for_media_routing_control")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="4780"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("com.android.media.flags.enable_privileged_routing_for_media_routing_control")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="4780"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("com.android.media.flags.enable_privileged_routing_for_media_routing_control")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="4780"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.app.usage.report_usage_stats_permission")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="4938"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.app.usage.report_usage_stats_permission")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="4938"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.app.usage.report_usage_stats_permission")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="4938"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.app.usage.report_usage_stats_permission")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="4938"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.hardware.biometrics.custom_biometric_prompt")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="5392"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.hardware.biometrics.custom_biometric_prompt")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="5392"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.hardware.biometrics.custom_biometric_prompt")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="5392"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.hardware.biometrics.custom_biometric_prompt")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="5392"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.hardware.biometrics.custom_biometric_prompt")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="5392"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.hardware.biometrics.custom_biometric_prompt")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="5392"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.hardware.biometrics.custom_biometric_prompt")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="5392"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.hardware.biometrics.custom_biometric_prompt")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="5392"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.hardware.biometrics.custom_biometric_prompt")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="5392"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.hardware.biometrics.custom_biometric_prompt")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="5392"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.hardware.biometrics.custom_biometric_prompt")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="5392"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.hardware.biometrics.custom_biometric_prompt")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="5392"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.permission.flags.sensitive_notification_app_protection")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="5535"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("com.android.server.telecom.flags.telecom_resolve_hidden_dependencies")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="5706"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("com.android.server.telecom.flags.telecom_resolve_hidden_dependencies")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="5706"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("com.android.server.telecom.flags.telecom_resolve_hidden_dependencies")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="5706"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("com.android.server.telecom.flags.telecom_resolve_hidden_dependencies")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="5706"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("com.android.server.telecom.flags.telecom_resolve_hidden_dependencies")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="5706"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("com.android.server.telecom.flags.telecom_resolve_hidden_dependencies")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="5706"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("com.android.server.telecom.flags.telecom_resolve_hidden_dependencies")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="5706"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("com.android.server.telecom.flags.telecom_resolve_hidden_dependencies")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="5706"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("com.android.server.telecom.flags.telecom_resolve_hidden_dependencies")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="5706"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("com.android.server.telecom.flags.telecom_resolve_hidden_dependencies")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="5714"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("com.android.server.telecom.flags.telecom_resolve_hidden_dependencies")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="5714"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("com.android.server.telecom.flags.telecom_resolve_hidden_dependencies")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="5714"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("com.android.server.telecom.flags.telecom_resolve_hidden_dependencies")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="5714"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("com.android.server.telecom.flags.telecom_resolve_hidden_dependencies")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="5714"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("com.android.server.telecom.flags.telecom_resolve_hidden_dependencies")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="5714"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("com.android.server.telecom.flags.telecom_resolve_hidden_dependencies")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="5714"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("com.android.server.telecom.flags.telecom_resolve_hidden_dependencies")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="5714"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("com.android.server.telecom.flags.telecom_resolve_hidden_dependencies")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="5714"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.app.contextualsearch.flags.enable_service")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="5829"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.app.contextualsearch.flags.enable_service")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="5829"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.content.pm.introduce_media_processing_type")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="5935"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.content.pm.introduce_media_processing_type")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="5935"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.content.pm.introduce_media_processing_type")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="5935"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.permission.flags.voice_activation_permission_apis")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="6084"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.permission.flags.voice_activation_permission_apis")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="6084"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.nfc.enable_nfc_mainline")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="6304"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.app.ondeviceintelligence.flags.enable_on_device_intelligence")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="6544"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.app.ondeviceintelligence.flags.enable_on_device_intelligence")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="6544"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.app.ondeviceintelligence.flags.enable_on_device_intelligence")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="6544"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.app.ondeviceintelligence.flags.enable_on_device_intelligence")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="6544"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.app.ondeviceintelligence.flags.enable_on_device_intelligence")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="6544"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.app.ondeviceintelligence.flags.enable_on_device_intelligence")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="6544"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.app.ondeviceintelligence.flags.enable_on_device_intelligence")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="6544"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.app.ondeviceintelligence.flags.enable_on_device_intelligence")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="6544"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.app.ondeviceintelligence.flags.enable_on_device_intelligence")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="6544"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.app.ondeviceintelligence.flags.enable_on_device_intelligence")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="6544"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.app.ondeviceintelligence.flags.enable_on_device_intelligence")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="6552"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.app.ondeviceintelligence.flags.enable_on_device_intelligence")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="6560"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.app.get_binding_uid_importance")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="6660"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.app.get_binding_uid_importance")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="6660"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.permission.flags.factory_reset_prep_permission_apis")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="6676"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("com.android.input.flags.override_key_behavior_permission_apis")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="6693"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.view.flags.sensitive_content_app_protection_api")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="6704"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.app.bic_client")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="6715"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.app.bic_client")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="6715"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.app.system_terms_of_address_enabled")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="6723"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.app.system_terms_of_address_enabled")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="6723"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.app.system_terms_of_address_enabled")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="6723"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.content.pm.emergency_install_permission")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="6732"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("com.android.server.power.feature.flags.enable_early_screen_timeout_detector")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="6747"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.security.fsverity_api")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/Manifest.java"
+ line="6755"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Class `LineBreakConfigSpan` is a flagged API and should be inside an `if (Flags.noBreakNoHyphenationSpan())` check (or annotate the surrounding method `buildForMeasurement` with `@FlaggedApi(Flags.FLAG_NO_BREAK_NO_HYPHENATION_SPAN) to transfer requirement to caller`)"
+ errorLine1=" LineBreakConfigSpan.class);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/text/MeasuredParagraph.java"
+ line="471"
+ column="25"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Class `LineBreakConfigSpan` is a flagged API and should be inside an `if (Flags.noBreakNoHyphenationSpan())` check (or annotate the surrounding method `buildForMeasurement` with `@FlaggedApi(Flags.FLAG_NO_BREAK_NO_HYPHENATION_SPAN) to transfer requirement to caller`)"
+ errorLine1=" LineBreakConfigSpan.class);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/text/MeasuredParagraph.java"
+ line="476"
+ column="25"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Class `LineBreakConfigSpan` is a flagged API and should be inside an `if (Flags.noBreakNoHyphenationSpan())` check (or annotate the surrounding method `buildForMeasurement` with `@FlaggedApi(Flags.FLAG_NO_BREAK_NO_HYPHENATION_SPAN) to transfer requirement to caller`)"
+ errorLine1=" LineBreakConfigSpan.class);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/text/MeasuredParagraph.java"
+ line="479"
+ column="25"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Class `LineBreakConfigSpan` is a flagged API and should be inside an `if (Flags.noBreakNoHyphenationSpan())` check (or annotate the surrounding method `buildForStaticLayoutInternal` with `@FlaggedApi(Flags.FLAG_NO_BREAK_NO_HYPHENATION_SPAN) to transfer requirement to caller`)"
+ errorLine1=" LineBreakConfigSpan.class);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/text/MeasuredParagraph.java"
+ line="625"
+ column="29"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Class `LineBreakConfigSpan` is a flagged API and should be inside an `if (Flags.noBreakNoHyphenationSpan())` check (or annotate the surrounding method `buildForStaticLayoutInternal` with `@FlaggedApi(Flags.FLAG_NO_BREAK_NO_HYPHENATION_SPAN) to transfer requirement to caller`)"
+ errorLine1=" LineBreakConfigSpan.class);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/text/MeasuredParagraph.java"
+ line="630"
+ column="29"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Class `LineBreakConfigSpan` is a flagged API and should be inside an `if (Flags.noBreakNoHyphenationSpan())` check (or annotate the surrounding method `buildForStaticLayoutInternal` with `@FlaggedApi(Flags.FLAG_NO_BREAK_NO_HYPHENATION_SPAN) to transfer requirement to caller`)"
+ errorLine1=" LineBreakConfigSpan.class);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/text/MeasuredParagraph.java"
+ line="634"
+ column="56"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `onAppendReplacementRun()` is a flagged API and should be inside an `if (Flags.noBreakNoHyphenationSpan())` check (or annotate the surrounding method `applyReplacementRun` with `@FlaggedApi(Flags.FLAG_NO_BREAK_NO_HYPHENATION_SPAN) to transfer requirement to caller`)"
+ errorLine1=" testCallback.onAppendReplacementRun(paint, end - start, width);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/text/MeasuredParagraph.java"
+ line="784"
+ column="13"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `TEXT_RUN_FLAG_LEFT_EDGE` is a flagged API and should be inside an `if (Flags.letterSpacingJustification())` check (or annotate the surrounding method `applyStyleRun` with `@FlaggedApi(Flags.FLAG_LETTER_SPACING_JUSTIFICATION) to transfer requirement to caller`)"
+ errorLine1=" | (Paint.TEXT_RUN_FLAG_LEFT_EDGE | Paint.TEXT_RUN_FLAG_RIGHT_EDGE));"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/text/MeasuredParagraph.java"
+ line="802"
+ column="34"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `TEXT_RUN_FLAG_RIGHT_EDGE` is a flagged API and should be inside an `if (Flags.letterSpacingJustification())` check (or annotate the surrounding method `applyStyleRun` with `@FlaggedApi(Flags.FLAG_LETTER_SPACING_JUSTIFICATION) to transfer requirement to caller`)"
+ errorLine1=" | (Paint.TEXT_RUN_FLAG_LEFT_EDGE | Paint.TEXT_RUN_FLAG_RIGHT_EDGE));"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/text/MeasuredParagraph.java"
+ line="802"
+ column="66"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `onAppendStyleRun()` is a flagged API and should be inside an `if (Flags.noBreakNoHyphenationSpan())` check (or annotate the surrounding method `applyStyleRun` with `@FlaggedApi(Flags.FLAG_NO_BREAK_NO_HYPHENATION_SPAN) to transfer requirement to caller`)"
+ errorLine1=" testCallback.onAppendStyleRun(paint, config, end - start, false);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/text/MeasuredParagraph.java"
+ line="814"
+ column="17"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `TEXT_RUN_FLAG_LEFT_EDGE` is a flagged API and should be inside an `if (Flags.letterSpacingJustification())` check (or annotate the surrounding method `applyStyleRun` with `@FlaggedApi(Flags.FLAG_LETTER_SPACING_JUSTIFICATION) to transfer requirement to caller`)"
+ errorLine1=" | (Paint.TEXT_RUN_FLAG_LEFT_EDGE | Paint.TEXT_RUN_FLAG_RIGHT_EDGE));"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/text/MeasuredParagraph.java"
+ line="828"
+ column="42"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `TEXT_RUN_FLAG_RIGHT_EDGE` is a flagged API and should be inside an `if (Flags.letterSpacingJustification())` check (or annotate the surrounding method `applyStyleRun` with `@FlaggedApi(Flags.FLAG_LETTER_SPACING_JUSTIFICATION) to transfer requirement to caller`)"
+ errorLine1=" | (Paint.TEXT_RUN_FLAG_LEFT_EDGE | Paint.TEXT_RUN_FLAG_RIGHT_EDGE));"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/text/MeasuredParagraph.java"
+ line="828"
+ column="74"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `onAppendStyleRun()` is a flagged API and should be inside an `if (Flags.noBreakNoHyphenationSpan())` check (or annotate the surrounding method `applyStyleRun` with `@FlaggedApi(Flags.FLAG_NO_BREAK_NO_HYPHENATION_SPAN) to transfer requirement to caller`)"
+ errorLine1=" testCallback.onAppendStyleRun(paint, config, levelEnd - levelStart, isRtl);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/text/MeasuredParagraph.java"
+ line="840"
+ column="25"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `getLineBreakConfig()` is a flagged API and should be inside an `if (Flags.noBreakNoHyphenationSpan())` check (or annotate the surrounding method `applyMetricsAffectingSpan` with `@FlaggedApi(Flags.FLAG_NO_BREAK_NO_HYPHENATION_SPAN) to transfer requirement to caller`)"
+ errorLine1=" mLineBreakConfigBuilder.merge(lbcSpan.getLineBreakConfig());"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/text/MeasuredParagraph.java"
+ line="888"
+ column="47"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `merge()` is a flagged API and should be inside an `if (Flags.noBreakNoHyphenationSpan())` check (or annotate the surrounding method `applyMetricsAffectingSpan` with `@FlaggedApi(Flags.FLAG_NO_BREAK_NO_HYPHENATION_SPAN) to transfer requirement to caller`)"
+ errorLine1=" mLineBreakConfigBuilder.merge(lbcSpan.getLineBreakConfig());"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/text/MeasuredParagraph.java"
+ line="888"
+ column="17"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `HYPHENATION_ENABLED` is a flagged API and should be inside an `if (Flags.noBreakNoHyphenationSpan())` check (or annotate the surrounding method `appendStyleRun` with `@FlaggedApi(Flags.FLAG_NO_BREAK_NO_HYPHENATION_SPAN) to transfer requirement to caller`)"
+ errorLine1=" == LineBreakConfig.HYPHENATION_ENABLED;"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/graphics/java/android/graphics/text/MeasuredText.java"
+ line="319"
+ column="40"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `onOutputBuffersAvailable()` is a flagged API and should be inside an `if (Flags.largeAudioFrame())` check (or annotate the surrounding method `handleCallback` with `@FlaggedApi(Flags.FLAG_LARGE_AUDIO_FRAME) to transfer requirement to caller`)"
+ errorLine1=" mCallback.onOutputBuffersAvailable("
+ errorLine2=" ^">
+ <location
+ file="frameworks/base/media/java/android/media/MediaCodec.java"
+ line="1985"
+ column="21"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `CONFIGURE_FLAG_DETACHED_SURFACE` is a flagged API and should be inside an `if (Flags.nullOutputSurface())` check (or annotate the surrounding method `configure` with `@FlaggedApi(Flags.FLAG_NULL_OUTPUT_SURFACE) to transfer requirement to caller`)"
+ errorLine1=" if (surface == null && (flags & CONFIGURE_FLAG_DETACHED_SURFACE) != 0 && !canDetach) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/media/java/android/media/MediaCodec.java"
+ line="2371"
+ column="45"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `CONFIGURE_FLAG_DETACHED_SURFACE` is a flagged API and should be inside an `if (Flags.nullOutputSurface())` check (or annotate the surrounding method `configure` with `@FlaggedApi(Flags.FLAG_NULL_OUTPUT_SURFACE) to transfer requirement to caller`)"
+ errorLine1=" if (surface == null && (flags & CONFIGURE_FLAG_DETACHED_SURFACE) != 0) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/media/java/android/media/MediaCodec.java"
+ line="2422"
+ column="45"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `FEATURE_DynamicColorAspects` is a flagged API and should be inside an `if (Flags.dynamicColorAspects())` check (or annotate the surrounding method `getDecoderFeatures` with `@FlaggedApi(Flags.FLAG_DYNAMIC_COLOR_ASPECTS) to transfer requirement to caller`)"
+ errorLine1=" features.add(new Feature(FEATURE_DynamicColorAspects, (1 << 8), true));"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/media/java/android/media/MediaCodecInfo.java"
+ line="832"
+ column="46"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `FEATURE_DetachedSurface` is a flagged API and should be inside an `if (Flags.nullOutputSurface())` check (or annotate the surrounding method `getDecoderFeatures` with `@FlaggedApi(Flags.FLAG_NULL_OUTPUT_SURFACE) to transfer requirement to caller`)"
+ errorLine1=" features.add(new Feature(FEATURE_DetachedSurface, (1 << 9), true));"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/media/java/android/media/MediaCodecInfo.java"
+ line="835"
+ column="46"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `FEATURE_HlgEditing` is a flagged API and should be inside an `if (Flags.hlgEditing())` check (or annotate the surrounding method `getEncoderFeatures` with `@FlaggedApi(Flags.FLAG_HLG_EDITING) to transfer requirement to caller`)"
+ errorLine1=" features.add(new Feature(FEATURE_HlgEditing, (1 << 6), true));"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/media/java/android/media/MediaCodecInfo.java"
+ line="856"
+ column="46"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `FEATURE_Roi` is a flagged API and should be inside an `if (Flags.regionOfInterest())` check (or annotate the surrounding method `getEncoderFeatures` with `@FlaggedApi(Flags.FLAG_REGION_OF_INTEREST) to transfer requirement to caller`)"
+ errorLine1=" features.add(new Feature(FEATURE_Roi, (1 << 7), true));"
+ errorLine2=" ~~~~~~~~~~~">
+ <location
+ file="frameworks/base/media/java/android/media/MediaCodecInfo.java"
+ line="859"
+ column="46"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `TYPE_HDMI_ARC` is a flagged API and should be inside an `if (Flags.enableAudioPoliciesDeviceAndBluetoothController())` check (or annotate the surrounding method `getDeviceTypeString` with `@FlaggedApi(Flags.FLAG_ENABLE_AUDIO_POLICIES_DEVICE_AND_BLUETOOTH_CONTROLLER) to transfer requirement to caller`)"
+ errorLine1=" case TYPE_HDMI_ARC:"
+ errorLine2=" ~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/media/java/android/media/MediaRoute2Info.java"
+ line="1030"
+ column="18"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `TYPE_HDMI_EARC` is a flagged API and should be inside an `if (Flags.enableAudioPoliciesDeviceAndBluetoothController())` check (or annotate the surrounding method `getDeviceTypeString` with `@FlaggedApi(Flags.FLAG_ENABLE_AUDIO_POLICIES_DEVICE_AND_BLUETOOTH_CONTROLLER) to transfer requirement to caller`)"
+ errorLine1=" case TYPE_HDMI_EARC:"
+ errorLine2=" ~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/media/java/android/media/MediaRoute2Info.java"
+ line="1032"
+ column="18"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `TYPE_REMOTE_TABLET` is a flagged API and should be inside an `if (Flags.enableNewMediaRoute2InfoTypes())` check (or annotate the surrounding method `getDeviceTypeString` with `@FlaggedApi(Flags.FLAG_ENABLE_NEW_MEDIA_ROUTE_2_INFO_TYPES) to transfer requirement to caller`)"
+ errorLine1=" case TYPE_REMOTE_TABLET:"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/media/java/android/media/MediaRoute2Info.java"
+ line="1050"
+ column="18"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `TYPE_REMOTE_TABLET_DOCKED` is a flagged API and should be inside an `if (Flags.enableNewMediaRoute2InfoTypes())` check (or annotate the surrounding method `getDeviceTypeString` with `@FlaggedApi(Flags.FLAG_ENABLE_NEW_MEDIA_ROUTE_2_INFO_TYPES) to transfer requirement to caller`)"
+ errorLine1=" case TYPE_REMOTE_TABLET_DOCKED:"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/media/java/android/media/MediaRoute2Info.java"
+ line="1052"
+ column="18"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `TYPE_REMOTE_COMPUTER` is a flagged API and should be inside an `if (Flags.enableNewMediaRoute2InfoTypes())` check (or annotate the surrounding method `getDeviceTypeString` with `@FlaggedApi(Flags.FLAG_ENABLE_NEW_MEDIA_ROUTE_2_INFO_TYPES) to transfer requirement to caller`)"
+ errorLine1=" case TYPE_REMOTE_COMPUTER:"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/media/java/android/media/MediaRoute2Info.java"
+ line="1054"
+ column="18"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `TYPE_REMOTE_GAME_CONSOLE` is a flagged API and should be inside an `if (Flags.enableNewMediaRoute2InfoTypes())` check (or annotate the surrounding method `getDeviceTypeString` with `@FlaggedApi(Flags.FLAG_ENABLE_NEW_MEDIA_ROUTE_2_INFO_TYPES) to transfer requirement to caller`)"
+ errorLine1=" case TYPE_REMOTE_GAME_CONSOLE:"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/media/java/android/media/MediaRoute2Info.java"
+ line="1056"
+ column="18"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `TYPE_REMOTE_CAR` is a flagged API and should be inside an `if (Flags.enableNewMediaRoute2InfoTypes())` check (or annotate the surrounding method `getDeviceTypeString` with `@FlaggedApi(Flags.FLAG_ENABLE_NEW_MEDIA_ROUTE_2_INFO_TYPES) to transfer requirement to caller`)"
+ errorLine1=" case TYPE_REMOTE_CAR:"
+ errorLine2=" ~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/media/java/android/media/MediaRoute2Info.java"
+ line="1058"
+ column="18"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `TYPE_REMOTE_SMARTWATCH` is a flagged API and should be inside an `if (Flags.enableNewMediaRoute2InfoTypes())` check (or annotate the surrounding method `getDeviceTypeString` with `@FlaggedApi(Flags.FLAG_ENABLE_NEW_MEDIA_ROUTE_2_INFO_TYPES) to transfer requirement to caller`)"
+ errorLine1=" case TYPE_REMOTE_SMARTWATCH:"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/media/java/android/media/MediaRoute2Info.java"
+ line="1060"
+ column="18"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `TYPE_REMOTE_SMARTPHONE` is a flagged API and should be inside an `if (Flags.enableNewMediaRoute2InfoTypes())` check (or annotate the surrounding method `getDeviceTypeString` with `@FlaggedApi(Flags.FLAG_ENABLE_NEW_MEDIA_ROUTE_2_INFO_TYPES) to transfer requirement to caller`)"
+ errorLine1=" case TYPE_REMOTE_SMARTPHONE:"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/media/java/android/media/MediaRoute2Info.java"
+ line="1062"
+ column="18"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `SUITABILITY_STATUS_SUITABLE_FOR_DEFAULT_TRANSFER` is a flagged API and should be inside an `if (Flags.enableBuiltInSpeakerRouteSuitabilityStatuses())` check (or annotate the surrounding method `Builder` with `@FlaggedApi(Flags.FLAG_ENABLE_BUILT_IN_SPEAKER_ROUTE_SUITABILITY_STATUSES) to transfer requirement to caller`)"
+ errorLine1=" mSuitabilityStatus = SUITABILITY_STATUS_SUITABLE_FOR_DEFAULT_TRANSFER;"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/media/java/android/media/MediaRoute2Info.java"
+ line="1122"
+ column="34"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `OPSTR_MEDIA_ROUTING_CONTROL` is a flagged API and should be inside an `if (Flags.enablePrivilegedRoutingForMediaRoutingControl())` check (or annotate the surrounding method `checkCallerHasOnlyRevocablePermissions` with `@FlaggedApi(Flags.FLAG_ENABLE_PRIVILEGED_ROUTING_FOR_MEDIA_ROUTING_CONTROL) to transfer requirement to caller`)"
+ errorLine1=" AppOpsManager.OPSTR_MEDIA_ROUTING_CONTROL,"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/media/java/android/media/MediaRouter2.java"
+ line="457"
+ column="47"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `CAPABILITY_TYPE_CALL_COMPOSER_BUSINESS_ONLY` is a flagged API and should be inside an `if (Flags.businessCallComposer())` check (or annotate the surrounding method `?` with `@FlaggedApi(Flags.FLAG_BUSINESS_CALL_COMPOSER) to transfer requirement to caller`)"
+ errorLine1=" CAPABILITY_TYPE_CALL_COMPOSER_BUSINESS_ONLY + 1;"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/ims/feature/MmTelFeature.java"
+ line="574"
+ column="17"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `CAPABILITY_TYPE_CALL_COMPOSER_BUSINESS_ONLY` is a flagged API and should be inside an `if (Flags.businessCallComposer())` check (or annotate the surrounding method `toString` with `@FlaggedApi(Flags.FLAG_BUSINESS_CALL_COMPOSER) to transfer requirement to caller`)"
+ errorLine1=" builder.append(isCapable(CAPABILITY_TYPE_CALL_COMPOSER_BUSINESS_ONLY));"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/ims/feature/MmTelFeature.java"
+ line="622"
+ column="38"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `isReliable()` is a flagged API and should be inside an `if (Flags.reliableMessage())` check (or annotate the surrounding method `equals` with `@FlaggedApi(Flags.FLAG_RELIABLE_MESSAGE) to transfer requirement to caller`)"
+ errorLine1=" || (other.isReliable() == mIsReliable))"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/hardware/location/NanoAppMessage.java"
+ line="269"
+ column="33"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `getMessageSequenceNumber()` is a flagged API and should be inside an `if (Flags.reliableMessage())` check (or annotate the surrounding method `equals` with `@FlaggedApi(Flags.FLAG_RELIABLE_MESSAGE) to transfer requirement to caller`)"
+ errorLine1=" || (other.getMessageSequenceNumber() == mMessageSequenceNumber));"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/hardware/location/NanoAppMessage.java"
+ line="271"
+ column="33"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `SERVICE_TYPE_MMS` is a flagged API and should be inside an `if (Flags.carrierEnabledSatelliteFlag())` check (or annotate the surrounding method `?` with `@FlaggedApi(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG) to transfer requirement to caller`)"
+ errorLine1=" public static final int LAST_SERVICE_TYPE = SERVICE_TYPE_MMS;"
+ errorLine2=" ~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/NetworkRegistrationInfo.java"
+ line="219"
+ column="49"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `SERVICE_TYPE_MMS` is a flagged API and should be inside an `if (Flags.carrierEnabledSatelliteFlag())` check (or annotate the surrounding method `serviceTypeToString` with `@FlaggedApi(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG) to transfer requirement to caller`)"
+ errorLine1=" case SERVICE_TYPE_MMS: return "MMS";"
+ errorLine2=" ~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/NetworkRegistrationInfo.java"
+ line="759"
+ column="18"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `getVibrationEffect()` is a flagged API and should be inside an `if (Flags.notificationChannelVibrationEffectApi())` check (or annotate the surrounding method `writeXml` with `@FlaggedApi(Flags.FLAG_NOTIFICATION_CHANNEL_VIBRATION_EFFECT_API) to transfer requirement to caller`)"
+ errorLine1=" if (getVibrationEffect() != null) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/app/NotificationChannel.java"
+ line="1333"
+ column="13"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `getVibrationEffect()` is a flagged API and should be inside an `if (Flags.notificationChannelVibrationEffectApi())` check (or annotate the surrounding method `writeXml` with `@FlaggedApi(Flags.FLAG_NOTIFICATION_CHANNEL_VIBRATION_EFFECT_API) to transfer requirement to caller`)"
+ errorLine1=" out.attribute(null, ATT_VIBRATION_EFFECT, vibrationToString(getVibrationEffect()));"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/app/NotificationChannel.java"
+ line="1334"
+ column="73"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `getVibrationEffect()` is a flagged API and should be inside an `if (Flags.notificationChannelVibrationEffectApi())` check (or annotate the surrounding method `toJson` with `@FlaggedApi(Flags.FLAG_NOTIFICATION_CHANNEL_VIBRATION_EFFECT_API) to transfer requirement to caller`)"
+ errorLine1=" if (getVibrationEffect() != null) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/app/NotificationChannel.java"
+ line="1416"
+ column="13"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `getVibrationEffect()` is a flagged API and should be inside an `if (Flags.notificationChannelVibrationEffectApi())` check (or annotate the surrounding method `toJson` with `@FlaggedApi(Flags.FLAG_NOTIFICATION_CHANNEL_VIBRATION_EFFECT_API) to transfer requirement to caller`)"
+ errorLine1=" record.put(ATT_VIBRATION_EFFECT, vibrationToString(getVibrationEffect()));"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/app/NotificationChannel.java"
+ line="1417"
+ column="64"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `getVibrationEffect()` is a flagged API and should be inside an `if (Flags.notificationChannelVibrationEffectApi())` check (or annotate the surrounding method `equals` with `@FlaggedApi(Flags.FLAG_NOTIFICATION_CHANNEL_VIBRATION_EFFECT_API) to transfer requirement to caller`)"
+ errorLine1=" && Objects.equals(getVibrationEffect(), that.getVibrationEffect())"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/app/NotificationChannel.java"
+ line="1545"
+ column="35"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `getVibrationEffect()` is a flagged API and should be inside an `if (Flags.notificationChannelVibrationEffectApi())` check (or annotate the surrounding method `equals` with `@FlaggedApi(Flags.FLAG_NOTIFICATION_CHANNEL_VIBRATION_EFFECT_API) to transfer requirement to caller`)"
+ errorLine1=" && Objects.equals(getVibrationEffect(), that.getVibrationEffect())"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/app/NotificationChannel.java"
+ line="1545"
+ column="57"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `getVibrationEffect()` is a flagged API and should be inside an `if (Flags.notificationChannelVibrationEffectApi())` check (or annotate the surrounding method `hashCode` with `@FlaggedApi(Flags.FLAG_NOTIFICATION_CHANNEL_VIBRATION_EFFECT_API) to transfer requirement to caller`)"
+ errorLine1=" mImportanceLockedDefaultApp, mOriginalImportance, getVibrationEffect(),"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/app/NotificationChannel.java"
+ line="1563"
+ column="67"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `addAutomaticZenRule()` is a flagged API and should be inside an `if (Flags.modesApi())` check (or annotate the surrounding method `addAutomaticZenRule` with `@FlaggedApi(Flags.FLAG_MODES_API) to transfer requirement to caller`)"
+ errorLine1=" return addAutomaticZenRule(automaticZenRule, /* fromUser= */ false);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/app/NotificationManager.java"
+ line="1368"
+ column="16"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `updateAutomaticZenRule()` is a flagged API and should be inside an `if (Flags.modesApi())` check (or annotate the surrounding method `updateAutomaticZenRule` with `@FlaggedApi(Flags.FLAG_MODES_API) to transfer requirement to caller`)"
+ errorLine1=" return updateAutomaticZenRule(id, automaticZenRule, /* fromUser= */ false);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/app/NotificationManager.java"
+ line="1404"
+ column="16"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `removeAutomaticZenRule()` is a flagged API and should be inside an `if (Flags.modesApi())` check (or annotate the surrounding method `removeAutomaticZenRule` with `@FlaggedApi(Flags.FLAG_MODES_API) to transfer requirement to caller`)"
+ errorLine1=" return removeAutomaticZenRule(id, /* fromUser= */ false);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/app/NotificationManager.java"
+ line="1473"
+ column="16"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `ROLLBACK_USER_IMPACT_LOW` is a flagged API and should be inside an `if (Flags.recoverabilityDetection())` check (or annotate the surrounding method `?` with `@FlaggedApi(Flags.FLAG_RECOVERABILITY_DETECTION) to transfer requirement to caller`)"
+ errorLine1=" public int rollbackImpactLevel = PackageManager.ROLLBACK_USER_IMPACT_LOW;"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/content/pm/PackageInstaller.java"
+ line="2789"
+ column="57"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `isArchived` is a flagged API and should be inside an `if (Flags.archiving())` check (or annotate the surrounding method `PackageItemInfo` with `@FlaggedApi(Flags.FLAG_ARCHIVING) to transfer requirement to caller`)"
+ errorLine1=" isArchived = orig.isArchived;"
+ errorLine2=" ~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/content/pm/PackageItemInfo.java"
+ line="204"
+ column="9"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `isArchived` is a flagged API and should be inside an `if (Flags.archiving())` check (or annotate the surrounding method `PackageItemInfo` with `@FlaggedApi(Flags.FLAG_ARCHIVING) to transfer requirement to caller`)"
+ errorLine1=" isArchived = orig.isArchived;"
+ errorLine2=" ~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/content/pm/PackageItemInfo.java"
+ line="204"
+ column="27"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `isArchived` is a flagged API and should be inside an `if (Flags.archiving())` check (or annotate the surrounding method `writeToParcel` with `@FlaggedApi(Flags.FLAG_ARCHIVING) to transfer requirement to caller`)"
+ errorLine1=" dest.writeBoolean(isArchived);"
+ errorLine2=" ~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/content/pm/PackageItemInfo.java"
+ line="470"
+ column="27"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `isArchived` is a flagged API and should be inside an `if (Flags.archiving())` check (or annotate the surrounding method `dumpDebug` with `@FlaggedApi(Flags.FLAG_ARCHIVING) to transfer requirement to caller`)"
+ errorLine1=" proto.write(PackageItemInfoProto.IS_ARCHIVED, isArchived);"
+ errorLine2=" ~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/content/pm/PackageItemInfo.java"
+ line="488"
+ column="55"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `isArchived` is a flagged API and should be inside an `if (Flags.archiving())` check (or annotate the surrounding method `PackageItemInfo` with `@FlaggedApi(Flags.FLAG_ARCHIVING) to transfer requirement to caller`)"
+ errorLine1=" isArchived = source.readBoolean();"
+ errorLine2=" ~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/content/pm/PackageItemInfo.java"
+ line="503"
+ column="9"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `PERSISTENT_DEVICE_ID_DEFAULT` is a flagged API and should be inside an `if (Flags.persistentDeviceIdApi())` check (or annotate the surrounding method `onPermissionsChanged` with `@FlaggedApi(Flags.FLAG_PERSISTENT_DEVICE_ID_API) to transfer requirement to caller`)"
+ errorLine1=" VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT)) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/content/pm/PackageManager.java"
+ line="766"
+ column="42"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `EXTRA_ARCHIVAL` is a flagged API and should be inside an `if (Flags.archiving())` check (or annotate the surrounding method `doHandlePackageEvent` with `@FlaggedApi(Flags.FLAG_ARCHIVING) to transfer requirement to caller`)"
+ errorLine1=" if (intent.getBooleanExtra(Intent.EXTRA_ARCHIVAL, false)) {"
+ errorLine2=" ~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/com/android/internal/content/PackageMonitor.java"
+ line="491"
+ column="55"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `ACTION_PACKAGE_UNSTOPPED` is a flagged API and should be inside an `if (Flags.stayStopped())` check (or annotate the surrounding method `doHandlePackageEvent` with `@FlaggedApi(Flags.FLAG_STAY_STOPPED) to transfer requirement to caller`)"
+ errorLine1=" } else if (Intent.ACTION_PACKAGE_UNSTOPPED.equals(action)) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/com/android/internal/content/PackageMonitor.java"
+ line="582"
+ column="27"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `TEXT_RUN_FLAG_LEFT_EDGE` is a flagged API and should be inside an `if (Flags.letterSpacingJustification())` check (or annotate the surrounding method `measureText` with `@FlaggedApi(Flags.FLAG_LETTER_SPACING_JUSTIFICATION) to transfer requirement to caller`)"
+ errorLine1=" setFlags(getFlags() | (TEXT_RUN_FLAG_LEFT_EDGE | TEXT_RUN_FLAG_RIGHT_EDGE));"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/graphics/java/android/graphics/Paint.java"
+ line="2587"
+ column="32"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `TEXT_RUN_FLAG_RIGHT_EDGE` is a flagged API and should be inside an `if (Flags.letterSpacingJustification())` check (or annotate the surrounding method `measureText` with `@FlaggedApi(Flags.FLAG_LETTER_SPACING_JUSTIFICATION) to transfer requirement to caller`)"
+ errorLine1=" setFlags(getFlags() | (TEXT_RUN_FLAG_LEFT_EDGE | TEXT_RUN_FLAG_RIGHT_EDGE));"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/graphics/java/android/graphics/Paint.java"
+ line="2587"
+ column="58"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `TEXT_RUN_FLAG_LEFT_EDGE` is a flagged API and should be inside an `if (Flags.letterSpacingJustification())` check (or annotate the surrounding method `measureText` with `@FlaggedApi(Flags.FLAG_LETTER_SPACING_JUSTIFICATION) to transfer requirement to caller`)"
+ errorLine1=" setFlags(getFlags() | (TEXT_RUN_FLAG_LEFT_EDGE | TEXT_RUN_FLAG_RIGHT_EDGE));"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/graphics/java/android/graphics/Paint.java"
+ line="2626"
+ column="32"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `TEXT_RUN_FLAG_RIGHT_EDGE` is a flagged API and should be inside an `if (Flags.letterSpacingJustification())` check (or annotate the surrounding method `measureText` with `@FlaggedApi(Flags.FLAG_LETTER_SPACING_JUSTIFICATION) to transfer requirement to caller`)"
+ errorLine1=" setFlags(getFlags() | (TEXT_RUN_FLAG_LEFT_EDGE | TEXT_RUN_FLAG_RIGHT_EDGE));"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/graphics/java/android/graphics/Paint.java"
+ line="2626"
+ column="58"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `TEXT_RUN_FLAG_LEFT_EDGE` is a flagged API and should be inside an `if (Flags.letterSpacingJustification())` check (or annotate the surrounding method `getTextWidths` with `@FlaggedApi(Flags.FLAG_LETTER_SPACING_JUSTIFICATION) to transfer requirement to caller`)"
+ errorLine1=" setFlags(getFlags() | (TEXT_RUN_FLAG_LEFT_EDGE | TEXT_RUN_FLAG_RIGHT_EDGE));"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/graphics/java/android/graphics/Paint.java"
+ line="2846"
+ column="32"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `TEXT_RUN_FLAG_RIGHT_EDGE` is a flagged API and should be inside an `if (Flags.letterSpacingJustification())` check (or annotate the surrounding method `getTextWidths` with `@FlaggedApi(Flags.FLAG_LETTER_SPACING_JUSTIFICATION) to transfer requirement to caller`)"
+ errorLine1=" setFlags(getFlags() | (TEXT_RUN_FLAG_LEFT_EDGE | TEXT_RUN_FLAG_RIGHT_EDGE));"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/graphics/java/android/graphics/Paint.java"
+ line="2846"
+ column="58"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `TEXT_RUN_FLAG_LEFT_EDGE` is a flagged API and should be inside an `if (Flags.letterSpacingJustification())` check (or annotate the surrounding method `getTextWidths` with `@FlaggedApi(Flags.FLAG_LETTER_SPACING_JUSTIFICATION) to transfer requirement to caller`)"
+ errorLine1=" setFlags(getFlags() | (TEXT_RUN_FLAG_LEFT_EDGE | TEXT_RUN_FLAG_RIGHT_EDGE));"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/graphics/java/android/graphics/Paint.java"
+ line="2936"
+ column="32"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `TEXT_RUN_FLAG_RIGHT_EDGE` is a flagged API and should be inside an `if (Flags.letterSpacingJustification())` check (or annotate the surrounding method `getTextWidths` with `@FlaggedApi(Flags.FLAG_LETTER_SPACING_JUSTIFICATION) to transfer requirement to caller`)"
+ errorLine1=" setFlags(getFlags() | (TEXT_RUN_FLAG_LEFT_EDGE | TEXT_RUN_FLAG_RIGHT_EDGE));"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/graphics/java/android/graphics/Paint.java"
+ line="2936"
+ column="58"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `isMgf1DigestsSpecified()` is a flagged API and should be inside an `if (Flags.mgf1DigestSetterV2())` check (or annotate the surrounding method `writeToParcel` with `@FlaggedApi(Flags.FLAG_MGF1_DIGEST_SETTER_V2) to transfer requirement to caller`)"
+ errorLine1=" if (mSpec.isMgf1DigestsSpecified()) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/keystore/java/android/security/keystore/ParcelableKeyGenParameterSpec.java"
+ line="98"
+ column="13"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `getMgf1Digests()` is a flagged API and should be inside an `if (Flags.mgf1DigestSetterV2())` check (or annotate the surrounding method `writeToParcel` with `@FlaggedApi(Flags.FLAG_MGF1_DIGEST_SETTER_V2) to transfer requirement to caller`)"
+ errorLine1=" out.writeStringList(List.copyOf(mSpec.getMgf1Digests()));"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/keystore/java/android/security/keystore/ParcelableKeyGenParameterSpec.java"
+ line="99"
+ column="45"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `computeBounds()` is a flagged API and should be inside an `if (Flags.exactComputeBounds())` check (or annotate the surrounding method `computeBounds` with `@FlaggedApi(Flags.FLAG_EXACT_COMPUTE_BOUNDS) to transfer requirement to caller`)"
+ errorLine1=" computeBounds(bounds);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/graphics/java/android/graphics/Path.java"
+ line="310"
+ column="9"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `onOneTimePermissionSessionTimeout()` is a flagged API and should be inside an `if (Flags.deviceAwarePermissionApisEnabled())` check (or annotate the surrounding method `notifyOneTimePermissionSessionTimeout` with `@FlaggedApi(Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED) to transfer requirement to caller`)"
+ errorLine1=" onOneTimePermissionSessionTimeout(packageName, deviceId);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/permission/PermissionControllerService.java"
+ line="672"
+ column="17"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `onRevokeSelfPermissionsOnKill()` is a flagged API and should be inside an `if (Flags.deviceAwarePermissionApisEnabled())` check (or annotate the surrounding method `revokeSelfPermissionsOnKill` with `@FlaggedApi(Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED) to transfer requirement to caller`)"
+ errorLine1=" onRevokeSelfPermissionsOnKill(packageName, permissions, deviceId,"
+ errorLine2=" ^">
+ <location
+ file="frameworks/base/core/java/android/permission/PermissionControllerService.java"
+ line="776"
+ column="21"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `PERSISTENT_DEVICE_ID_DEFAULT` is a flagged API and should be inside an `if (Flags.persistentDeviceIdApi())` check (or annotate the surrounding method `getIndicatorAppOpUsageData` with `@FlaggedApi(Flags.FLAG_PERSISTENT_DEVICE_ID_API) to transfer requirement to caller`)"
+ errorLine1=" VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/permission/PermissionManager.java"
+ line="1342"
+ column="38"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `PERSISTENT_DEVICE_ID_DEFAULT` is a flagged API and should be inside an `if (Flags.persistentDeviceIdApi())` check (or annotate the surrounding method `getPersistentDeviceId` with `@FlaggedApi(Flags.FLAG_PERSISTENT_DEVICE_ID_API) to transfer requirement to caller`)"
+ errorLine1=" persistentDeviceId = VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT;"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/permission/PermissionManager.java"
+ line="1951"
+ column="55"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `onPermissionsChanged()` is a flagged API and should be inside an `if (Flags.deviceAwarePermissionApisEnabled())` check (or annotate the surrounding method `handleMessage` with `@FlaggedApi(Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED) to transfer requirement to caller`)"
+ errorLine1=" mListener.onPermissionsChanged(uid, persistentDeviceId);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/permission/PermissionManager.java"
+ line="2040"
+ column="21"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `getPersistentDeviceId()` is a flagged API and should be inside an `if (Flags.vdmPublicApis())` check (or annotate the surrounding method `getOpUsageDataForAllDevices` with `@FlaggedApi(Flags.FLAG_VDM_PUBLIC_APIS) to transfer requirement to caller`)"
+ errorLine1=" persistentDeviceIds.add(virtualDevices.get(num).getPersistentDeviceId());"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/permission/PermissionUsageHelper.java"
+ line="381"
+ column="37"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `PERSISTENT_DEVICE_ID_DEFAULT` is a flagged API and should be inside an `if (Flags.persistentDeviceIdApi())` check (or annotate the surrounding method `getOpUsageDataForAllDevices` with `@FlaggedApi(Flags.FLAG_PERSISTENT_DEVICE_ID_API) to transfer requirement to caller`)"
+ errorLine1=" persistentDeviceIds.add(VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/permission/PermissionUsageHelper.java"
+ line="383"
+ column="54"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `PERSISTENT_DEVICE_ID_DEFAULT` is a flagged API and should be inside an `if (Flags.persistentDeviceIdApi())` check (or annotate the surrounding method `getOpUsagesByDevice` with `@FlaggedApi(Flags.FLAG_PERSISTENT_DEVICE_ID_API) to transfer requirement to caller`)"
+ errorLine1=" VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT)) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/permission/PermissionUsageHelper.java"
+ line="492"
+ column="42"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `hasSimultaneousCallingRestriction()` is a flagged API and should be inside an `if (Flags.simultaneousCallingIndications())` check (or annotate the surrounding method `Builder` with `@FlaggedApi(Flags.FLAG_SIMULTANEOUS_CALLING_INDICATIONS) to transfer requirement to caller`)"
+ errorLine1=" if (phoneAccount.hasSimultaneousCallingRestriction()) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telecomm/java/android/telecom/PhoneAccount.java"
+ line="585"
+ column="17"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `getSimultaneousCallingRestriction()` is a flagged API and should be inside an `if (Flags.simultaneousCallingIndications())` check (or annotate the surrounding method `Builder` with `@FlaggedApi(Flags.FLAG_SIMULTANEOUS_CALLING_INDICATIONS) to transfer requirement to caller`)"
+ errorLine1=" mSimultaneousCallingRestriction = phoneAccount.getSimultaneousCallingRestriction();"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telecomm/java/android/telecom/PhoneAccount.java"
+ line="586"
+ column="51"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `hasSimultaneousCallingRestriction()` is a flagged API and should be inside an `if (Flags.simultaneousCallingIndications())` check (or annotate the surrounding method `toString` with `@FlaggedApi(Flags.FLAG_SIMULTANEOUS_CALLING_INDICATIONS) to transfer requirement to caller`)"
+ errorLine1=" if (hasSimultaneousCallingRestriction()) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telecomm/java/android/telecom/PhoneAccount.java"
+ line="1292"
+ column="13"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `STATE_PLAYBACK_SUPPRESSED` is a flagged API and should be inside an `if (Flags.enableNotifyingActivityManagerWithMediaSessionStatusChange())` check (or annotate the surrounding method `isActive` with `@FlaggedApi(Flags.FLAG_ENABLE_NOTIFYING_ACTIVITY_MANAGER_WITH_MEDIA_SESSION_STATUS_CHANGE) to transfer requirement to caller`)"
+ errorLine1=" case PlaybackState.STATE_PLAYBACK_SUPPRESSED:"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/media/java/android/media/session/PlaybackState.java"
+ line="541"
+ column="32"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `STATE_PLAYBACK_SUPPRESSED` is a flagged API and should be inside an `if (Flags.enableNotifyingActivityManagerWithMediaSessionStatusChange())` check (or annotate the surrounding method `getStringForStateInt` with `@FlaggedApi(Flags.FLAG_ENABLE_NOTIFYING_ACTIVITY_MANAGER_WITH_MEDIA_SESSION_STATUS_CHANGE) to transfer requirement to caller`)"
+ errorLine1=" case STATE_PLAYBACK_SUPPRESSED:"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/media/java/android/media/session/PlaybackState.java"
+ line="587"
+ column="18"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1="@FlaggedApi("com.android.server.power.optimization.power_monitor_api")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/os/PowerMonitor.java"
+ line="39"
+ column="13"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1="@FlaggedApi("com.android.server.power.optimization.power_monitor_api")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/os/PowerMonitor.java"
+ line="39"
+ column="13"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1="@FlaggedApi("com.android.server.power.optimization.power_monitor_api")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/os/PowerMonitor.java"
+ line="39"
+ column="13"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1="@FlaggedApi("com.android.server.power.optimization.power_monitor_api")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/os/PowerMonitor.java"
+ line="39"
+ column="13"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1="@FlaggedApi("com.android.server.power.optimization.power_monitor_api")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/os/PowerMonitor.java"
+ line="39"
+ column="13"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1="@FlaggedApi("com.android.server.power.optimization.power_monitor_api")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/os/PowerMonitor.java"
+ line="39"
+ column="13"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1="@FlaggedApi("com.android.server.power.optimization.power_monitor_api")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/os/PowerMonitor.java"
+ line="39"
+ column="13"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1="@FlaggedApi("com.android.server.power.optimization.power_monitor_api")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/os/PowerMonitor.java"
+ line="39"
+ column="13"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1="@FlaggedApi("com.android.server.power.optimization.power_monitor_api")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/os/PowerMonitor.java"
+ line="39"
+ column="13"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1="@FlaggedApi("com.android.server.power.optimization.power_monitor_api")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/os/PowerMonitor.java"
+ line="39"
+ column="13"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1="@FlaggedApi("com.android.server.power.optimization.power_monitor_api")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/os/PowerMonitor.java"
+ line="39"
+ column="13"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1="@FlaggedApi("com.android.server.power.optimization.power_monitor_api")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/os/PowerMonitor.java"
+ line="39"
+ column="13"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1="@FlaggedApi("com.android.server.power.optimization.power_monitor_api")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/os/PowerMonitor.java"
+ line="39"
+ column="13"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1="@FlaggedApi("com.android.server.power.optimization.power_monitor_api")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/os/PowerMonitor.java"
+ line="39"
+ column="13"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1="@FlaggedApi("com.android.server.power.optimization.power_monitor_api")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/os/PowerMonitor.java"
+ line="39"
+ column="13"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1="@FlaggedApi("com.android.server.power.optimization.power_monitor_api")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/os/PowerMonitor.java"
+ line="39"
+ column="13"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1="@FlaggedApi("com.android.server.power.optimization.power_monitor_api")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/os/PowerMonitor.java"
+ line="39"
+ column="13"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1="@FlaggedApi("com.android.server.power.optimization.power_monitor_api")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/os/PowerMonitor.java"
+ line="39"
+ column="13"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1="@FlaggedApi("com.android.server.power.optimization.power_monitor_api")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/os/PowerMonitor.java"
+ line="39"
+ column="13"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @FlaggedApi("com.android.server.power.optimization.power_monitor_api")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/os/PowerMonitor.java"
+ line="49"
+ column="17"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @FlaggedApi("com.android.server.power.optimization.power_monitor_api")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/os/PowerMonitor.java"
+ line="49"
+ column="17"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @FlaggedApi("com.android.server.power.optimization.power_monitor_api")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/os/PowerMonitor.java"
+ line="57"
+ column="17"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @FlaggedApi("com.android.server.power.optimization.power_monitor_api")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/os/PowerMonitor.java"
+ line="57"
+ column="17"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @FlaggedApi("com.android.server.power.optimization.power_monitor_api")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/os/PowerMonitor.java"
+ line="94"
+ column="17"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @FlaggedApi("com.android.server.power.optimization.power_monitor_api")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/os/PowerMonitor.java"
+ line="103"
+ column="17"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @FlaggedApi("com.android.server.power.optimization.power_monitor_api")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/os/PowerMonitor.java"
+ line="103"
+ column="17"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @FlaggedApi("com.android.server.power.optimization.power_monitor_api")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/os/PowerMonitor.java"
+ line="115"
+ column="17"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @FlaggedApi("com.android.server.power.optimization.power_monitor_api")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/os/PowerMonitor.java"
+ line="123"
+ column="17"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @FlaggedApi("com.android.server.power.optimization.power_monitor_api")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/os/PowerMonitor.java"
+ line="129"
+ column="17"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1="@FlaggedApi("com.android.server.power.optimization.power_monitor_api")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/os/PowerMonitorReadings.java"
+ line="29"
+ column="13"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1="@FlaggedApi("com.android.server.power.optimization.power_monitor_api")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/os/PowerMonitorReadings.java"
+ line="29"
+ column="13"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1="@FlaggedApi("com.android.server.power.optimization.power_monitor_api")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/os/PowerMonitorReadings.java"
+ line="29"
+ column="13"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1="@FlaggedApi("com.android.server.power.optimization.power_monitor_api")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/os/PowerMonitorReadings.java"
+ line="29"
+ column="13"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1="@FlaggedApi("com.android.server.power.optimization.power_monitor_api")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/os/PowerMonitorReadings.java"
+ line="29"
+ column="13"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1="@FlaggedApi("com.android.server.power.optimization.power_monitor_api")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/os/PowerMonitorReadings.java"
+ line="29"
+ column="13"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1="@FlaggedApi("com.android.server.power.optimization.power_monitor_api")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/os/PowerMonitorReadings.java"
+ line="29"
+ column="13"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1="@FlaggedApi("com.android.server.power.optimization.power_monitor_api")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/os/PowerMonitorReadings.java"
+ line="29"
+ column="13"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1="@FlaggedApi("com.android.server.power.optimization.power_monitor_api")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/os/PowerMonitorReadings.java"
+ line="29"
+ column="13"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1="@FlaggedApi("com.android.server.power.optimization.power_monitor_api")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/os/PowerMonitorReadings.java"
+ line="29"
+ column="13"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1="@FlaggedApi("com.android.server.power.optimization.power_monitor_api")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/os/PowerMonitorReadings.java"
+ line="29"
+ column="13"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1="@FlaggedApi("com.android.server.power.optimization.power_monitor_api")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/os/PowerMonitorReadings.java"
+ line="29"
+ column="13"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1="@FlaggedApi("com.android.server.power.optimization.power_monitor_api")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/os/PowerMonitorReadings.java"
+ line="29"
+ column="13"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1="@FlaggedApi("com.android.server.power.optimization.power_monitor_api")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/os/PowerMonitorReadings.java"
+ line="29"
+ column="13"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1="@FlaggedApi("com.android.server.power.optimization.power_monitor_api")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/os/PowerMonitorReadings.java"
+ line="29"
+ column="13"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @FlaggedApi("com.android.server.power.optimization.power_monitor_api")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/os/PowerMonitorReadings.java"
+ line="31"
+ column="17"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @FlaggedApi("com.android.server.power.optimization.power_monitor_api")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/os/PowerMonitorReadings.java"
+ line="31"
+ column="17"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @FlaggedApi("com.android.server.power.optimization.power_monitor_api")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/os/PowerMonitorReadings.java"
+ line="60"
+ column="17"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @FlaggedApi("com.android.server.power.optimization.power_monitor_api")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/os/PowerMonitorReadings.java"
+ line="72"
+ column="17"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `NETWORK_VALIDATION_UNSUPPORTED` is a flagged API and should be inside an `if (Flags.networkValidation())` check (or annotate the surrounding method `PreciseDataConnectionState` with `@FlaggedApi(Flags.FLAG_NETWORK_VALIDATION) to transfer requirement to caller`)"
+ errorLine1=" .build(), null, NETWORK_VALIDATION_UNSUPPORTED);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/PreciseDataConnectionState.java"
+ line="143"
+ column="41"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `NETWORK_VALIDATION_UNSUPPORTED` is a flagged API and should be inside an `if (Flags.networkValidation())` check (or annotate the surrounding method `networkValidationStatusToString` with `@FlaggedApi(Flags.FLAG_NETWORK_VALIDATION) to transfer requirement to caller`)"
+ errorLine1=" case NETWORK_VALIDATION_UNSUPPORTED: return "unsupported";"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/PreciseDataConnectionState.java"
+ line="456"
+ column="18"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `NETWORK_VALIDATION_NOT_REQUESTED` is a flagged API and should be inside an `if (Flags.networkValidation())` check (or annotate the surrounding method `networkValidationStatusToString` with `@FlaggedApi(Flags.FLAG_NETWORK_VALIDATION) to transfer requirement to caller`)"
+ errorLine1=" case NETWORK_VALIDATION_NOT_REQUESTED: return "not requested";"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/PreciseDataConnectionState.java"
+ line="457"
+ column="18"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `NETWORK_VALIDATION_IN_PROGRESS` is a flagged API and should be inside an `if (Flags.networkValidation())` check (or annotate the surrounding method `networkValidationStatusToString` with `@FlaggedApi(Flags.FLAG_NETWORK_VALIDATION) to transfer requirement to caller`)"
+ errorLine1=" case NETWORK_VALIDATION_IN_PROGRESS: return "in progress";"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/PreciseDataConnectionState.java"
+ line="458"
+ column="18"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `NETWORK_VALIDATION_SUCCESS` is a flagged API and should be inside an `if (Flags.networkValidation())` check (or annotate the surrounding method `networkValidationStatusToString` with `@FlaggedApi(Flags.FLAG_NETWORK_VALIDATION) to transfer requirement to caller`)"
+ errorLine1=" case NETWORK_VALIDATION_SUCCESS: return "success";"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/PreciseDataConnectionState.java"
+ line="459"
+ column="18"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `NETWORK_VALIDATION_FAILURE` is a flagged API and should be inside an `if (Flags.networkValidation())` check (or annotate the surrounding method `networkValidationStatusToString` with `@FlaggedApi(Flags.FLAG_NETWORK_VALIDATION) to transfer requirement to caller`)"
+ errorLine1=" case NETWORK_VALIDATION_FAILURE: return "failure";"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/PreciseDataConnectionState.java"
+ line="460"
+ column="18"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `NETWORK_VALIDATION_UNSUPPORTED` is a flagged API and should be inside an `if (Flags.networkValidation())` check (or annotate the surrounding method `?` with `@FlaggedApi(Flags.FLAG_NETWORK_VALIDATION) to transfer requirement to caller`)"
+ errorLine1=" NETWORK_VALIDATION_UNSUPPORTED;"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/PreciseDataConnectionState.java"
+ line="508"
+ column="17"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `LINE_BREAK_WORD_STYLE_AUTO` is a flagged API and should be inside an `if (Flags.wordStyleAuto())` check (or annotate the surrounding method `createMeasuredParagraphsFromPrecomputedText` with `@FlaggedApi(Flags.FLAG_WORD_STYLE_AUTO) to transfer requirement to caller`)"
+ errorLine1=" if (config.getLineBreakWordStyle() == LineBreakConfig.LINE_BREAK_WORD_STYLE_AUTO"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/text/PrecomputedText.java"
+ line="461"
+ column="63"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `merge()` is a flagged API and should be inside an `if (Flags.noBreakNoHyphenationSpan())` check (or annotate the surrounding method `createMeasuredParagraphsFromPrecomputedText` with `@FlaggedApi(Flags.FLAG_NO_BREAK_NO_HYPHENATION_SPAN) to transfer requirement to caller`)"
+ errorLine1=" config = new LineBreakConfig.Builder()"
+ errorLine2=" ^">
+ <location
+ file="frameworks/base/core/java/android/text/PrecomputedText.java"
+ line="464"
+ column="22"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `LINE_BREAK_WORD_STYLE_AUTO` is a flagged API and should be inside an `if (Flags.wordStyleAuto())` check (or annotate the surrounding method `createMeasuredParagraphs` with `@FlaggedApi(Flags.FLAG_WORD_STYLE_AUTO) to transfer requirement to caller`)"
+ errorLine1=" if (config.getLineBreakWordStyle() == LineBreakConfig.LINE_BREAK_WORD_STYLE_AUTO"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/text/PrecomputedText.java"
+ line="515"
+ column="71"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `isResumed()` is a flagged API and should be inside an `if (Flags.enableNfcMainline())` check (or annotate the surrounding method `onListItemClick` with `@FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE) to transfer requirement to caller`)"
+ errorLine1=" if (!isResumed()) {"
+ errorLine2=" ~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/preference/PreferenceActivity.java"
+ line="1071"
+ column="14"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Class `PromptContentViewParcelable` is a flagged API and should be inside an `if (Flags.customBiometricPrompt())` check (or annotate the surrounding method `PromptInfo` with `@FlaggedApi(Flags.FLAG_CUSTOM_BIOMETRIC_PROMPT) to transfer requirement to caller`)"
+ errorLine1=" mContentView = in.readParcelable(PromptContentViewParcelable.class.getClassLoader(),"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/hardware/biometrics/PromptInfo.java"
+ line="75"
+ column="42"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Class `PromptContentViewParcelable` is a flagged API and should be inside an `if (Flags.customBiometricPrompt())` check (or annotate the surrounding method `PromptInfo` with `@FlaggedApi(Flags.FLAG_CUSTOM_BIOMETRIC_PROMPT) to transfer requirement to caller`)"
+ errorLine1=" PromptContentViewParcelable.class);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/hardware/biometrics/PromptInfo.java"
+ line="76"
+ column="17"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="This is a flagged API and should be inside an `if (Flags.customBiometricPrompt())` check (or annotate the surrounding method `isContentViewMoreOptionsButtonUsed` with `@FlaggedApi(Flags.FLAG_CUSTOM_BIOMETRIC_PROMPT) to transfer requirement to caller`)"
+ errorLine1=" && mContentView instanceof PromptContentViewWithMoreOptionsButton;"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/hardware/biometrics/PromptInfo.java"
+ line="214"
+ column="44"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="This is a flagged API and should be inside an `if (Flags.customBiometricPrompt())` check (or annotate the surrounding method `setContentView` with `@FlaggedApi(Flags.FLAG_CUSTOM_BIOMETRIC_PROMPT) to transfer requirement to caller`)"
+ errorLine1=" mContentView = (PromptContentViewParcelable) view;"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/hardware/biometrics/PromptInfo.java"
+ line="258"
+ column="25"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.media.tv.flags.enable_ad_service_fw")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/R.java"
+ line="610"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.media.tv.flags.enable_ad_service_fw")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/R.java"
+ line="610"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.media.tv.flags.enable_ad_service_fw")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/R.java"
+ line="610"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.media.tv.flags.enable_ad_service_fw")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/R.java"
+ line="610"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.content.pm.relative_reference_intent_filters")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/R.java"
+ line="693"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.security.asm_restrictions_enabled")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/R.java"
+ line="759"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.nfc.nfc_read_polling_loop")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/R.java"
+ line="1300"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.view.flags.sensitive_content_app_protection_api")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/R.java"
+ line="2782"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.content.res.default_locale")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/R.java"
+ line="3023"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.service.controls.flags.Flags.FLAG_HOME_PANEL_DREAM")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/R.java"
+ line="3599"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.service.controls.flags.Flags.FLAG_HOME_PANEL_DREAM")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/R.java"
+ line="3599"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.service.controls.flags.Flags.FLAG_HOME_PANEL_DREAM")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/R.java"
+ line="3599"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.service.controls.flags.Flags.FLAG_HOME_PANEL_DREAM")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/R.java"
+ line="3599"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.content.res.manifest_flagging")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/R.java"
+ line="4290"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.content.pm.relative_reference_intent_filters")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/R.java"
+ line="4870"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.content.pm.relative_reference_intent_filters")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/R.java"
+ line="4970"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.content.pm.relative_reference_intent_filters")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/R.java"
+ line="4979"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.content.pm.relative_reference_intent_filters")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/R.java"
+ line="5032"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.companion.virtual.flags.vdm_custom_ime")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/R.java"
+ line="6857"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.view.inputmethod.ime_switcher_revamp")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/R.java"
+ line="7587"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.view.inputmethod.ime_switcher_revamp")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/R.java"
+ line="7587"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.view.inputmethod.ime_switcher_revamp")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/R.java"
+ line="7587"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.view.inputmethod.ime_switcher_revamp")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/R.java"
+ line="7587"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.content.pm.sdk_lib_independence")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/R.java"
+ line="9481"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.content.pm.sdk_lib_independence")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/R.java"
+ line="9481"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.content.pm.sdk_lib_independence")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/R.java"
+ line="9481"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.content.pm.sdk_lib_independence")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/R.java"
+ line="9481"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.content.pm.relative_reference_intent_filters")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/R.java"
+ line="10701"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.content.pm.relative_reference_intent_filters")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/R.java"
+ line="10727"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.content.pm.relative_reference_intent_filters")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/R.java"
+ line="10767"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.content.pm.relative_reference_intent_filters")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/R.java"
+ line="10776"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.content.pm.relative_reference_intent_filters")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/R.java"
+ line="10785"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.security.content_uri_permission_apis")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/R.java"
+ line="11122"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("com.android.text.flags.use_bounds_for_width")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/R.java"
+ line="12404"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.nfc.nfc_observe_mode")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/R.java"
+ line="12438"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.view.inputmethod.connectionless_handwriting")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/R.java"
+ line="13485"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.multiuser.enable_system_user_only_for_services_and_providers")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/R.java"
+ line="13672"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("com.android.text.flags.use_bounds_for_width")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/R.java"
+ line="15472"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("com.android.text.flags.fix_line_height_for_locale")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/R.java"
+ line="15520"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.view.flags.toolkit_set_frame_rate_read_only")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/R.java"
+ line="16364"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("com.android.window.flags.enforce_edge_to_edge")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/R.java"
+ line="16561"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.permission.flags.retail_demo_role_enabled")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/R.java"
+ line="18455"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.permission.flags.wallet_role_enabled")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/R.java"
+ line="18473"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.security.content_uri_permission_apis")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/R.java"
+ line="25110"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.security.asm_restrictions_enabled")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/R.java"
+ line="25837"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.security.asm_restrictions_enabled")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/R.java"
+ line="27173"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.view.inputmethod.ime_switcher_revamp")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/R.java"
+ line="41370"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.companion.virtual.flags.vdm_custom_ime")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/R.java"
+ line="41608"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.view.inputmethod.ime_switcher_revamp")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/R.java"
+ line="41645"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.content.res.default_locale")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/R.java"
+ line="44145"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.nfc.nfc_read_polling_loop")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/R.java"
+ line="45932"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.nfc.nfc_read_polling_loop")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/R.java"
+ line="45956"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.nfc.nfc_read_polling_loop")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/R.java"
+ line="45970"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.nfc.nfc_read_polling_loop")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/R.java"
+ line="45996"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("com.android.text.flags.use_bounds_for_width")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/R.java"
+ line="53416"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("com.android.text.flags.use_bounds_for_width")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/R.java"
+ line="53416"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("com.android.text.flags.use_bounds_for_width")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/R.java"
+ line="53416"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("com.android.text.flags.use_bounds_for_width")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/R.java"
+ line="53416"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("com.android.text.flags.use_bounds_for_width")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/R.java"
+ line="55227"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("com.android.text.flags.fix_line_height_for_locale")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/R.java"
+ line="55238"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("com.android.text.flags.use_bounds_for_width")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/R.java"
+ line="55249"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.view.flags.sensitive_content_app_protection_api")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/R.java"
+ line="62287"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @android.annotation.FlaggedApi("android.view.flags.sensitive_content_app_protection_api")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="out/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/gen/android/R.srcjar!/android/R.java"
+ line="64240"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `METADATA_KEY_COMMENT_SHORT_DESCRIPTION` is a flagged API and should be inside an `if (Flags.hdRadioImproved())` check (or annotate the surrounding method `?` with `@FlaggedApi(Flags.FLAG_HD_RADIO_IMPROVED) to transfer requirement to caller`)"
+ errorLine1=" METADATA_KEYS_TYPE.put(METADATA_KEY_COMMENT_SHORT_DESCRIPTION, METADATA_TYPE_TEXT);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/hardware/radio/RadioMetadata.java"
+ line="249"
+ column="32"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `METADATA_KEY_COMMENT_ACTUAL_TEXT` is a flagged API and should be inside an `if (Flags.hdRadioImproved())` check (or annotate the surrounding method `?` with `@FlaggedApi(Flags.FLAG_HD_RADIO_IMPROVED) to transfer requirement to caller`)"
+ errorLine1=" METADATA_KEYS_TYPE.put(METADATA_KEY_COMMENT_ACTUAL_TEXT, METADATA_TYPE_TEXT);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/hardware/radio/RadioMetadata.java"
+ line="250"
+ column="32"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `METADATA_KEY_COMMERCIAL` is a flagged API and should be inside an `if (Flags.hdRadioImproved())` check (or annotate the surrounding method `?` with `@FlaggedApi(Flags.FLAG_HD_RADIO_IMPROVED) to transfer requirement to caller`)"
+ errorLine1=" METADATA_KEYS_TYPE.put(METADATA_KEY_COMMERCIAL, METADATA_TYPE_TEXT);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/hardware/radio/RadioMetadata.java"
+ line="251"
+ column="32"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `METADATA_KEY_UFIDS` is a flagged API and should be inside an `if (Flags.hdRadioImproved())` check (or annotate the surrounding method `?` with `@FlaggedApi(Flags.FLAG_HD_RADIO_IMPROVED) to transfer requirement to caller`)"
+ errorLine1=" METADATA_KEYS_TYPE.put(METADATA_KEY_UFIDS, METADATA_TYPE_TEXT_ARRAY);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/hardware/radio/RadioMetadata.java"
+ line="252"
+ column="32"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `METADATA_KEY_HD_STATION_NAME_SHORT` is a flagged API and should be inside an `if (Flags.hdRadioImproved())` check (or annotate the surrounding method `?` with `@FlaggedApi(Flags.FLAG_HD_RADIO_IMPROVED) to transfer requirement to caller`)"
+ errorLine1=" METADATA_KEYS_TYPE.put(METADATA_KEY_HD_STATION_NAME_SHORT, METADATA_TYPE_TEXT);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/hardware/radio/RadioMetadata.java"
+ line="253"
+ column="32"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `METADATA_KEY_HD_STATION_NAME_LONG` is a flagged API and should be inside an `if (Flags.hdRadioImproved())` check (or annotate the surrounding method `?` with `@FlaggedApi(Flags.FLAG_HD_RADIO_IMPROVED) to transfer requirement to caller`)"
+ errorLine1=" METADATA_KEYS_TYPE.put(METADATA_KEY_HD_STATION_NAME_LONG, METADATA_TYPE_TEXT);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/hardware/radio/RadioMetadata.java"
+ line="254"
+ column="32"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `METADATA_KEY_HD_SUBCHANNELS_AVAILABLE` is a flagged API and should be inside an `if (Flags.hdRadioImproved())` check (or annotate the surrounding method `?` with `@FlaggedApi(Flags.FLAG_HD_RADIO_IMPROVED) to transfer requirement to caller`)"
+ errorLine1=" METADATA_KEYS_TYPE.put(METADATA_KEY_HD_SUBCHANNELS_AVAILABLE, METADATA_TYPE_INT);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/hardware/radio/RadioMetadata.java"
+ line="255"
+ column="32"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `isPrivateProfile()` is a flagged API and should be inside an `if (Flags.allowPrivateProfile())` check (or annotate the surrounding method `fetchPrivateProfileUserHandle` with `@FlaggedApi(Flags.FLAG_ALLOW_PRIVATE_PROFILE) to transfer requirement to caller`)"
+ errorLine1=" if (userInfo.isPrivateProfile()) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/com/android/internal/app/ResolverActivity.java"
+ line="827"
+ column="17"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `getDefaultLocale()` is a flagged API and should be inside an `if (Flags.defaultLocale())` check (or annotate the surrounding method `updateConfigurationImpl` with `@FlaggedApi(Flags.FLAG_DEFAULT_LOCALE) to transfer requirement to caller`)"
+ errorLine1=" if (Flags.defaultLocale() && (lc.getDefaultLocale() != null)) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/content/res/ResourcesImpl.java"
+ line="474"
+ column="55"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `getDefaultLocale()` is a flagged API and should be inside an `if (Flags.defaultLocale())` check (or annotate the surrounding method `updateConfigurationImpl` with `@FlaggedApi(Flags.FLAG_DEFAULT_LOCALE) to transfer requirement to caller`)"
+ errorLine1=" if (Flags.defaultLocale() && (lc.getDefaultLocale() != null)) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/content/res/ResourcesImpl.java"
+ line="515"
+ column="51"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `ROLLBACK_USER_IMPACT_LOW` is a flagged API and should be inside an `if (Flags.recoverabilityDetection())` check (or annotate the surrounding method `RollbackInfo` with `@FlaggedApi(Flags.FLAG_RECOVERABILITY_DETECTION) to transfer requirement to caller`)"
+ errorLine1=" PackageManager.ROLLBACK_USER_IMPACT_LOW);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/content/rollback/RollbackInfo.java"
+ line="80"
+ column="32"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `getTransferReason()` is a flagged API and should be inside an `if (Flags.enableBuiltInSpeakerRouteSuitabilityStatuses())` check (or annotate the surrounding method `toString` with `@FlaggedApi(Flags.FLAG_ENABLE_BUILT_IN_SPEAKER_ROUTE_SUITABILITY_STATUSES) to transfer requirement to caller`)"
+ errorLine1=" .append(getTransferReason())"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/media/java/android/media/RoutingSessionInfo.java"
+ line="528"
+ column="25"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `TRANSFER_REASON_FALLBACK` is a flagged API and should be inside an `if (Flags.enableBuiltInSpeakerRouteSuitabilityStatuses())` check (or annotate the surrounding method `?` with `@FlaggedApi(Flags.FLAG_ENABLE_BUILT_IN_SPEAKER_ROUTE_SUITABILITY_STATUSES) to transfer requirement to caller`)"
+ errorLine1=" @TransferReason private int mTransferReason = TRANSFER_REASON_FALLBACK;"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/media/java/android/media/RoutingSessionInfo.java"
+ line="590"
+ column="55"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `SCREEN_RECORDING_STATE_NOT_VISIBLE` is a flagged API and should be inside an `if (Flags.screenRecordingCallbacks())` check (or annotate the surrounding method `?` with `@FlaggedApi(Flags.FLAG_SCREEN_RECORDING_CALLBACKS) to transfer requirement to caller`)"
+ errorLine1=" private @ScreenRecordingState int mState = SCREEN_RECORDING_STATE_NOT_VISIBLE;"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/view/ScreenRecordingCallbacks.java"
+ line="54"
+ column="48"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `SCREEN_RECORDING_STATE_VISIBLE` is a flagged API and should be inside an `if (Flags.screenRecordingCallbacks())` check (or annotate the surrounding method `onScreenRecordingStateChanged` with `@FlaggedApi(Flags.FLAG_SCREEN_RECORDING_CALLBACKS) to transfer requirement to caller`)"
+ errorLine1=" ? SCREEN_RECORDING_STATE_VISIBLE"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/view/ScreenRecordingCallbacks.java"
+ line="85"
+ column="51"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `SCREEN_RECORDING_STATE_NOT_VISIBLE` is a flagged API and should be inside an `if (Flags.screenRecordingCallbacks())` check (or annotate the surrounding method `onScreenRecordingStateChanged` with `@FlaggedApi(Flags.FLAG_SCREEN_RECORDING_CALLBACKS) to transfer requirement to caller`)"
+ errorLine1=" : SCREEN_RECORDING_STATE_NOT_VISIBLE;"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/view/ScreenRecordingCallbacks.java"
+ line="86"
+ column="51"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `SCREEN_RECORDING_STATE_VISIBLE` is a flagged API and should be inside an `if (Flags.screenRecordingCallbacks())` check (or annotate the surrounding method `addCallback` with `@FlaggedApi(Flags.FLAG_SCREEN_RECORDING_CALLBACKS) to transfer requirement to caller`)"
+ errorLine1=" ? SCREEN_RECORDING_STATE_VISIBLE"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/view/ScreenRecordingCallbacks.java"
+ line="96"
+ column="39"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `SCREEN_RECORDING_STATE_NOT_VISIBLE` is a flagged API and should be inside an `if (Flags.screenRecordingCallbacks())` check (or annotate the surrounding method `addCallback` with `@FlaggedApi(Flags.FLAG_SCREEN_RECORDING_CALLBACKS) to transfer requirement to caller`)"
+ errorLine1=" : SCREEN_RECORDING_STATE_NOT_VISIBLE;"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/view/ScreenRecordingCallbacks.java"
+ line="97"
+ column="39"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `FOREGROUND_SERVICE_TYPE_MEDIA_PROCESSING` is a flagged API and should be inside an `if (Flags.introduceMediaProcessingType())` check (or annotate the surrounding method `foregroundServiceTypeToLabel` with `@FlaggedApi(Flags.FLAG_INTRODUCE_MEDIA_PROCESSING_TYPE) to transfer requirement to caller`)"
+ errorLine1=" case FOREGROUND_SERVICE_TYPE_MEDIA_PROCESSING:"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/content/pm/ServiceInfo.java"
+ line="707"
+ column="18"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `isPrivateProfile()` is a flagged API and should be inside an `if (Flags.allowPrivateProfile())` check (or annotate the surrounding method `setLaunchUserSpecificMessage` with `@FlaggedApi(Flags.FLAG_ALLOW_PRIVATE_PROFILE) to transfer requirement to caller`)"
+ errorLine1=" if (userInfo != null && userInfo.isPrivateProfile()) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/com/android/internal/app/SetScreenLockDialogActivity.java"
+ line="146"
+ column="37"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @FlaggedApi("com.android.media.flags.enable_privileged_routing_for_media_routing_control")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/provider/Settings.java"
+ line="665"
+ column="17"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @FlaggedApi("com.android.server.biometrics.face_vhal_feature")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/provider/Settings.java"
+ line="11022"
+ column="21"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @FlaggedApi("com.android.server.biometrics.face_vhal_feature")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/provider/Settings.java"
+ line="11030"
+ column="21"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @FlaggedApi("com.android.wifi.flags.shared_connectivity_broadcast_receiver_test_api")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManager.java"
+ line="300"
+ column="17"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `getInputTransferToken()` is a flagged API and should be inside an `if (Flags.surfaceControlInputReceiver())` check (or annotate the surrounding method `createSurfaceView` with `@FlaggedApi(Flags.FLAG_SURFACE_CONTROL_INPUT_RECEIVER) to transfer requirement to caller`)"
+ errorLine1=" : attachedSurfaceControl.getInputTransferToken(),"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/window/SplashScreenView.java"
+ line="342"
+ column="35"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `uptimeNanos()` is a flagged API and should be inside an `if (Flags.adpfGpuReportActualWorkDuration())` check (or annotate the surrounding method `getTime` with `@FlaggedApi(Flags.FLAG_ADPF_GPU_REPORT_ACTUAL_WORK_DURATION) to transfer requirement to caller`)"
+ errorLine1=" return SystemClock.uptimeNanos() / 1000;"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/com/android/internal/util/StatLogger.java"
+ line="94"
+ column="16"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `setUseBoundsForWidth()` is a flagged API and should be inside an `if (Flags.useBoundsForWidth())` check (or annotate the surrounding method `generate` with `@FlaggedApi(Flags.FLAG_USE_BOUNDS_FOR_WIDTH) to transfer requirement to caller`)"
+ errorLine1=" final LineBreaker lineBreaker = new LineBreaker.Builder()"
+ errorLine2=" ^">
+ <location
+ file="frameworks/base/core/java/android/text/StaticLayout.java"
+ line="823"
+ column="41"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `computeDrawingBoundingBox()` is a flagged API and should be inside an `if (Flags.useBoundsForWidth())` check (or annotate the surrounding method `computeDrawingBoundingBox` with `@FlaggedApi(Flags.FLAG_USE_BOUNDS_FOR_WIDTH) to transfer requirement to caller`)"
+ errorLine1=" mDrawingBounds = super.computeDrawingBoundingBox();"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/text/StaticLayout.java"
+ line="1578"
+ column="30"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `createNoBreakSpan()` is a flagged API and should be inside an `if (Flags.noBreakNoHyphenationSpan())` check (or annotate the surrounding method `applyStyles` with `@FlaggedApi(Flags.FLAG_NO_BREAK_NO_HYPHENATION_SPAN) to transfer requirement to caller`)"
+ errorLine1=" buffer.setSpan(LineBreakConfigSpan.createNoBreakSpan(),"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/content/res/StringBlock.java"
+ line="297"
+ column="32"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `createNoHyphenationSpan()` is a flagged API and should be inside an `if (Flags.noBreakNoHyphenationSpan())` check (or annotate the surrounding method `applyStyles` with `@FlaggedApi(Flags.FLAG_NO_BREAK_NO_HYPHENATION_SPAN) to transfer requirement to caller`)"
+ errorLine1=" buffer.setSpan(LineBreakConfigSpan.createNoHyphenationSpan(),"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/content/res/StringBlock.java"
+ line="301"
+ column="32"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `LINE_BREAK_STYLE_UNSPECIFIED` is a flagged API and should be inside an `if (Flags.noBreakNoHyphenationSpan())` check (or annotate the surrounding method `applyStyles` with `@FlaggedApi(Flags.FLAG_NO_BREAK_NO_HYPHENATION_SPAN) to transfer requirement to caller`)"
+ errorLine1=" int lbStyle = LineBreakConfig.LINE_BREAK_STYLE_UNSPECIFIED;"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/content/res/StringBlock.java"
+ line="387"
+ column="51"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `LINE_BREAK_STYLE_UNSPECIFIED` is a flagged API and should be inside an `if (Flags.noBreakNoHyphenationSpan())` check (or annotate the surrounding method `applyStyles` with `@FlaggedApi(Flags.FLAG_NO_BREAK_NO_HYPHENATION_SPAN) to transfer requirement to caller`)"
+ errorLine1=" int lbWordStyle = LineBreakConfig.LINE_BREAK_STYLE_UNSPECIFIED;"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/content/res/StringBlock.java"
+ line="403"
+ column="55"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `LINE_BREAK_STYLE_UNSPECIFIED` is a flagged API and should be inside an `if (Flags.noBreakNoHyphenationSpan())` check (or annotate the surrounding method `applyStyles` with `@FlaggedApi(Flags.FLAG_NO_BREAK_NO_HYPHENATION_SPAN) to transfer requirement to caller`)"
+ errorLine1=" if (lbStyle != LineBreakConfig.LINE_BREAK_STYLE_UNSPECIFIED"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/content/res/StringBlock.java"
+ line="415"
+ column="52"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `LINE_BREAK_WORD_STYLE_UNSPECIFIED` is a flagged API and should be inside an `if (Flags.noBreakNoHyphenationSpan())` check (or annotate the surrounding method `applyStyles` with `@FlaggedApi(Flags.FLAG_NO_BREAK_NO_HYPHENATION_SPAN) to transfer requirement to caller`)"
+ errorLine1=" || lbWordStyle != LineBreakConfig.LINE_BREAK_WORD_STYLE_UNSPECIFIED) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/content/res/StringBlock.java"
+ line="416"
+ column="63"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `LineBreakConfigSpan()` is a flagged API and should be inside an `if (Flags.noBreakNoHyphenationSpan())` check (or annotate the surrounding method `applyStyles` with `@FlaggedApi(Flags.FLAG_NO_BREAK_NO_HYPHENATION_SPAN) to transfer requirement to caller`)"
+ errorLine1=" buffer.setSpan(new LineBreakConfigSpan("
+ errorLine2=" ^">
+ <location
+ file="frameworks/base/core/java/android/content/res/StringBlock.java"
+ line="417"
+ column="40"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `HYPHENATION_UNSPECIFIED` is a flagged API and should be inside an `if (Flags.noBreakNoHyphenationSpan())` check (or annotate the surrounding method `applyStyles` with `@FlaggedApi(Flags.FLAG_NO_BREAK_NO_HYPHENATION_SPAN) to transfer requirement to caller`)"
+ errorLine1=" LineBreakConfig.HYPHENATION_UNSPECIFIED)),"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/content/res/StringBlock.java"
+ line="419"
+ column="57"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `setServiceCapabilities()` is a flagged API and should be inside an `if (Flags.dataOnlyCellularService())` check (or annotate the surrounding method `createFromParcel` with `@FlaggedApi(Flags.FLAG_DATA_ONLY_CELLULAR_SERVICE) to transfer requirement to caller`)"
+ errorLine1=" return new Builder()"
+ errorLine2=" ^">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/SubscriptionInfo.java"
+ line="957"
+ column="20"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `setTransferStatus()` is a flagged API and should be inside an `if (Flags.supportPsimToEsimConversion())` check (or annotate the surrounding method `createFromParcel` with `@FlaggedApi(Flags.FLAG_SUPPORT_PSIM_TO_ESIM_CONVERSION) to transfer requirement to caller`)"
+ errorLine1=" return new Builder()"
+ errorLine2=" ^">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/SubscriptionInfo.java"
+ line="957"
+ column="20"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `SERVICE_CAPABILITY_DATA` is a flagged API and should be inside an `if (Flags.dataOnlyCellularService())` check (or annotate the surrounding method `?` with `@FlaggedApi(Flags.FLAG_DATA_ONLY_CELLULAR_SERVICE) to transfer requirement to caller`)"
+ errorLine1=" public static final int SERVICE_CAPABILITY_MAX = SERVICE_CAPABILITY_DATA;"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/SubscriptionManager.java"
+ line="1436"
+ column="54"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `SERVICE_CAPABILITY_VOICE` is a flagged API and should be inside an `if (Flags.dataOnlyCellularService())` check (or annotate the surrounding method `?` with `@FlaggedApi(Flags.FLAG_DATA_ONLY_CELLULAR_SERVICE) to transfer requirement to caller`)"
+ errorLine1=" serviceCapabilityToBitmask(SERVICE_CAPABILITY_VOICE);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/SubscriptionManager.java"
+ line="1443"
+ column="40"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `SERVICE_CAPABILITY_SMS` is a flagged API and should be inside an `if (Flags.dataOnlyCellularService())` check (or annotate the surrounding method `?` with `@FlaggedApi(Flags.FLAG_DATA_ONLY_CELLULAR_SERVICE) to transfer requirement to caller`)"
+ errorLine1=" serviceCapabilityToBitmask(SERVICE_CAPABILITY_SMS);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/SubscriptionManager.java"
+ line="1450"
+ column="40"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `SERVICE_CAPABILITY_DATA` is a flagged API and should be inside an `if (Flags.dataOnlyCellularService())` check (or annotate the surrounding method `?` with `@FlaggedApi(Flags.FLAG_DATA_ONLY_CELLULAR_SERVICE) to transfer requirement to caller`)"
+ errorLine1=" serviceCapabilityToBitmask(SERVICE_CAPABILITY_DATA);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/SubscriptionManager.java"
+ line="1457"
+ column="40"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="This is a flagged API and should be inside an `if (Flags.telecomResolveHiddenDependencies())` check (or annotate the surrounding method `addOnSubscriptionsChangedListener` with `@FlaggedApi(Flags.FLAG_TELECOM_RESOLVE_HIDDEN_DEPENDENCIES) to transfer requirement to caller`)"
+ errorLine1=" TelephonyRegistryManager telephonyRegistryManager = (TelephonyRegistryManager)"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/SubscriptionManager.java"
+ line="1696"
+ column="62"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `addOnSubscriptionsChangedListener()` is a flagged API and should be inside an `if (Flags.telecomResolveHiddenDependencies())` check (or annotate the surrounding method `addOnSubscriptionsChangedListener` with `@FlaggedApi(Flags.FLAG_TELECOM_RESOLVE_HIDDEN_DEPENDENCIES) to transfer requirement to caller`)"
+ errorLine1=" telephonyRegistryManager.addOnSubscriptionsChangedListener(listener,"
+ errorLine2=" ^">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/SubscriptionManager.java"
+ line="1699"
+ column="13"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="This is a flagged API and should be inside an `if (Flags.telecomResolveHiddenDependencies())` check (or annotate the surrounding method `removeOnSubscriptionsChangedListener` with `@FlaggedApi(Flags.FLAG_TELECOM_RESOLVE_HIDDEN_DEPENDENCIES) to transfer requirement to caller`)"
+ errorLine1=" TelephonyRegistryManager telephonyRegistryManager = (TelephonyRegistryManager)"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/SubscriptionManager.java"
+ line="1726"
+ column="62"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `removeOnSubscriptionsChangedListener()` is a flagged API and should be inside an `if (Flags.telecomResolveHiddenDependencies())` check (or annotate the surrounding method `removeOnSubscriptionsChangedListener` with `@FlaggedApi(Flags.FLAG_TELECOM_RESOLVE_HIDDEN_DEPENDENCIES) to transfer requirement to caller`)"
+ errorLine1=" telephonyRegistryManager.removeOnSubscriptionsChangedListener(listener);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/SubscriptionManager.java"
+ line="1729"
+ column="13"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="This is a flagged API and should be inside an `if (Flags.telecomResolveHiddenDependencies())` check (or annotate the surrounding method `addOnOpportunisticSubscriptionsChangedListener` with `@FlaggedApi(Flags.FLAG_TELECOM_RESOLVE_HIDDEN_DEPENDENCIES) to transfer requirement to caller`)"
+ errorLine1=" TelephonyRegistryManager telephonyRegistryManager = (TelephonyRegistryManager)"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/SubscriptionManager.java"
+ line="1784"
+ column="62"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `addOnOpportunisticSubscriptionsChangedListener()` is a flagged API and should be inside an `if (Flags.telecomResolveHiddenDependencies())` check (or annotate the surrounding method `addOnOpportunisticSubscriptionsChangedListener` with `@FlaggedApi(Flags.FLAG_TELECOM_RESOLVE_HIDDEN_DEPENDENCIES) to transfer requirement to caller`)"
+ errorLine1=" telephonyRegistryManager.addOnOpportunisticSubscriptionsChangedListener("
+ errorLine2=" ^">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/SubscriptionManager.java"
+ line="1787"
+ column="13"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="This is a flagged API and should be inside an `if (Flags.telecomResolveHiddenDependencies())` check (or annotate the surrounding method `removeOnOpportunisticSubscriptionsChangedListener` with `@FlaggedApi(Flags.FLAG_TELECOM_RESOLVE_HIDDEN_DEPENDENCIES) to transfer requirement to caller`)"
+ errorLine1=" TelephonyRegistryManager telephonyRegistryManager = (TelephonyRegistryManager)"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/SubscriptionManager.java"
+ line="1808"
+ column="62"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `removeOnOpportunisticSubscriptionsChangedListener()` is a flagged API and should be inside an `if (Flags.telecomResolveHiddenDependencies())` check (or annotate the surrounding method `removeOnOpportunisticSubscriptionsChangedListener` with `@FlaggedApi(Flags.FLAG_TELECOM_RESOLVE_HIDDEN_DEPENDENCIES) to transfer requirement to caller`)"
+ errorLine1=" telephonyRegistryManager.removeOnOpportunisticSubscriptionsChangedListener(listener);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/SubscriptionManager.java"
+ line="1811"
+ column="13"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `SERVICE_CAPABILITY_VOICE` is a flagged API and should be inside an `if (Flags.dataOnlyCellularService())` check (or annotate the surrounding method `getServiceCapabilitiesSet` with `@FlaggedApi(Flags.FLAG_DATA_ONLY_CELLULAR_SERVICE) to transfer requirement to caller`)"
+ errorLine1=" for (int i = SERVICE_CAPABILITY_VOICE; i <= SERVICE_CAPABILITY_MAX; i++) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/SubscriptionManager.java"
+ line="4800"
+ column="22"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `CREATOR` is a flagged API and should be inside an `if (Flags.surfaceControlInputReceiver())` check (or annotate the surrounding method `SurfacePackage` with `@FlaggedApi(Flags.FLAG_SURFACE_CONTROL_INPUT_RECEIVER) to transfer requirement to caller`)"
+ errorLine1=" mInputTransferToken = InputTransferToken.CREATOR.createFromParcel(in);"
+ errorLine2=" ~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/view/SurfaceControlViewHost.java"
+ line="196"
+ column="54"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `writeToParcel()` is a flagged API and should be inside an `if (Flags.surfaceControlInputReceiver())` check (or annotate the surrounding method `writeToParcel` with `@FlaggedApi(Flags.FLAG_SURFACE_CONTROL_INPUT_RECEIVER) to transfer requirement to caller`)"
+ errorLine1=" mInputTransferToken.writeToParcel(out, flags);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/view/SurfaceControlViewHost.java"
+ line="276"
+ column="13"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `getInputTransferToken()` is a flagged API and should be inside an `if (Flags.surfaceControlInputReceiver())` check (or annotate the surrounding method `toString` with `@FlaggedApi(Flags.FLAG_SURFACE_CONTROL_INPUT_RECEIVER) to transfer requirement to caller`)"
+ errorLine1=" return "{inputTransferToken=" + getInputTransferToken() + " remoteInterface=""
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/view/SurfaceControlViewHost.java"
+ line="309"
+ column="45"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `InputTransferToken()` is a flagged API and should be inside an `if (Flags.surfaceControlInputReceiver())` check (or annotate the surrounding method `SurfaceControlViewHost` with `@FlaggedApi(Flags.FLAG_SURFACE_CONTROL_INPUT_RECEIVER) to transfer requirement to caller`)"
+ errorLine1=" this(context, display, hostToken == null ? null : new InputTransferToken(hostToken),"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/view/SurfaceControlViewHost.java"
+ line="352"
+ column="59"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `transferTouchGesture()` is a flagged API and should be inside an `if (Flags.surfaceControlInputReceiver())` check (or annotate the surrounding method `transferTouchGestureToHost` with `@FlaggedApi(Flags.FLAG_SURFACE_CONTROL_INPUT_RECEIVER) to transfer requirement to caller`)"
+ errorLine1=" return wm.transferTouchGesture(getInputTransferToken(), mWm.mHostInputTransferToken);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/view/SurfaceControlViewHost.java"
+ line="602"
+ column="16"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `getInputTransferToken()` is a flagged API and should be inside an `if (Flags.surfaceControlInputReceiver())` check (or annotate the surrounding method `requestEmbeddedFocus` with `@FlaggedApi(Flags.FLAG_SURFACE_CONTROL_INPUT_RECEIVER) to transfer requirement to caller`)"
+ errorLine1=" mSurfacePackage.getInputTransferToken(), gainFocus);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/view/SurfaceView.java"
+ line="2155"
+ column="21"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `uptimeNanos()` is a flagged API and should be inside an `if (Flags.adpfGpuReportActualWorkDuration())` check (or annotate the surrounding method `uptimeMillis$ravenwood` with `@FlaggedApi(Flags.FLAG_ADPF_GPU_REPORT_ACTUAL_WORK_DURATION) to transfer requirement to caller`)"
+ errorLine1=" return uptimeNanos() / 1_000_000;"
+ errorLine2=" ~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/os/SystemClock.java"
+ line="202"
+ column="16"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `uptimeNanos()` is a flagged API and should be inside an `if (Flags.adpfGpuReportActualWorkDuration())` check (or annotate the surrounding method `elapsedRealtimeNanos$ravenwood` with `@FlaggedApi(Flags.FLAG_ADPF_GPU_REPORT_ACTUAL_WORK_DURATION) to transfer requirement to caller`)"
+ errorLine1=" return uptimeNanos() + (DateUtils.HOUR_IN_MILLIS * 1_000_000);"
+ errorLine2=" ~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/os/SystemClock.java"
+ line="276"
+ column="16"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @FlaggedApi("com.android.server.power.optimization.power_monitor_api")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/os/health/SystemHealthManager.java"
+ line="231"
+ column="17"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="@FlaggedApi should specify an actual flag constant; raw strings are discouraged (and more importantly, **not enforced**)"
+ errorLine1=" @FlaggedApi("com.android.server.power.optimization.power_monitor_api")"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/os/health/SystemHealthManager.java"
+ line="287"
+ column="17"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `null()` is a flagged API and should be inside an `if (Flags.vdmPublicApis())` check (or annotate the surrounding method `setupVirtualDeviceListener` with `@FlaggedApi(Flags.FLAG_VDM_PUBLIC_APIS) to transfer requirement to caller`)"
+ errorLine1=" mVirtualDeviceListener = new VirtualDeviceManager.VirtualDeviceListener() {"
+ errorLine2=" ^">
+ <location
+ file="frameworks/base/core/java/android/hardware/SystemSensorManager.java"
+ line="612"
+ column="34"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="This is a flagged API and should be inside an `if (Flags.vdmPublicApis())` check (or annotate the surrounding method `setupVirtualDeviceListener` with `@FlaggedApi(Flags.FLAG_VDM_PUBLIC_APIS) to transfer requirement to caller`)"
+ errorLine1=" mVirtualDeviceListener = new VirtualDeviceManager.VirtualDeviceListener() {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/hardware/SystemSensorManager.java"
+ line="612"
+ column="38"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `registerVirtualDeviceListener()` is a flagged API and should be inside an `if (Flags.vdmPublicApis())` check (or annotate the surrounding method `setupVirtualDeviceListener` with `@FlaggedApi(Flags.FLAG_VDM_PUBLIC_APIS) to transfer requirement to caller`)"
+ errorLine1=" mVdm.registerVirtualDeviceListener(mContext.getMainExecutor(), mVirtualDeviceListener);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/hardware/SystemSensorManager.java"
+ line="627"
+ column="9"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Class `SecurityStateManager` is a flagged API and should be inside an `if (Flags.securityStateService())` check (or annotate the surrounding method `?` with `@FlaggedApi(Flags.FLAG_SECURITY_STATE_SERVICE) to transfer requirement to caller`)"
+ errorLine1=" registerService(Context.SECURITY_STATE_SERVICE, SecurityStateManager.class,"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/app/SystemServiceRegistry.java"
+ line="676"
+ column="57"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `SECURITY_STATE_SERVICE` is a flagged API and should be inside an `if (Flags.securityStateService())` check (or annotate the surrounding method `?` with `@FlaggedApi(Flags.FLAG_SECURITY_STATE_SERVICE) to transfer requirement to caller`)"
+ errorLine1=" registerService(Context.SECURITY_STATE_SERVICE, SecurityStateManager.class,"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/app/SystemServiceRegistry.java"
+ line="676"
+ column="33"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `SECURITY_STATE_SERVICE` is a flagged API and should be inside an `if (Flags.securityStateService())` check (or annotate the surrounding method `createService` with `@FlaggedApi(Flags.FLAG_SECURITY_STATE_SERVICE) to transfer requirement to caller`)"
+ errorLine1=" Context.SECURITY_STATE_SERVICE);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/app/SystemServiceRegistry.java"
+ line="682"
+ column="41"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `SecurityStateManager()` is a flagged API and should be inside an `if (Flags.securityStateService())` check (or annotate the surrounding method `createService` with `@FlaggedApi(Flags.FLAG_SECURITY_STATE_SERVICE) to transfer requirement to caller`)"
+ errorLine1=" return new SecurityStateManager(service);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/app/SystemServiceRegistry.java"
+ line="684"
+ column="32"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Class `TelephonyRegistryManager` is a flagged API and should be inside an `if (Flags.telecomResolveHiddenDependencies())` check (or annotate the surrounding method `?` with `@FlaggedApi(Flags.FLAG_TELECOM_RESOLVE_HIDDEN_DEPENDENCIES) to transfer requirement to caller`)"
+ errorLine1=" registerService(Context.TELEPHONY_REGISTRY_SERVICE, TelephonyRegistryManager.class,"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/app/SystemServiceRegistry.java"
+ line="743"
+ column="61"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `TelephonyRegistryManager()` is a flagged API and should be inside an `if (Flags.telecomResolveHiddenDependencies())` check (or annotate the surrounding method `createService` with `@FlaggedApi(Flags.FLAG_TELECOM_RESOLVE_HIDDEN_DEPENDENCIES) to transfer requirement to caller`)"
+ errorLine1=" return new TelephonyRegistryManager(ctx);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/app/SystemServiceRegistry.java"
+ line="747"
+ column="28"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Class `TvAdManager` is a flagged API and should be inside an `if (Flags.enableAdServiceFw())` check (or annotate the surrounding method `?` with `@FlaggedApi(Flags.FLAG_ENABLE_AD_SERVICE_FW) to transfer requirement to caller`)"
+ errorLine1=" registerService(Context.TV_AD_SERVICE, TvAdManager.class,"
+ errorLine2=" ~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/app/SystemServiceRegistry.java"
+ line="1019"
+ column="48"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `TV_AD_SERVICE` is a flagged API and should be inside an `if (Flags.enableAdServiceFw())` check (or annotate the surrounding method `?` with `@FlaggedApi(Flags.FLAG_ENABLE_AD_SERVICE_FW) to transfer requirement to caller`)"
+ errorLine1=" registerService(Context.TV_AD_SERVICE, TvAdManager.class,"
+ errorLine2=" ~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/app/SystemServiceRegistry.java"
+ line="1019"
+ column="33"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `TV_AD_SERVICE` is a flagged API and should be inside an `if (Flags.enableAdServiceFw())` check (or annotate the surrounding method `createService` with `@FlaggedApi(Flags.FLAG_ENABLE_AD_SERVICE_FW) to transfer requirement to caller`)"
+ errorLine1=" ServiceManager.getServiceOrThrow(Context.TV_AD_SERVICE);"
+ errorLine2=" ~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/app/SystemServiceRegistry.java"
+ line="1025"
+ column="74"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `TvAdManager()` is a flagged API and should be inside an `if (Flags.enableAdServiceFw())` check (or annotate the surrounding method `createService` with `@FlaggedApi(Flags.FLAG_ENABLE_AD_SERVICE_FW) to transfer requirement to caller`)"
+ errorLine1=" return new TvAdManager(service, ctx.getUserId());"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/app/SystemServiceRegistry.java"
+ line="1028"
+ column="32"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Class `PersistentDataBlockManager` is a flagged API and should be inside an `if (Flags.frpEnforcement())` check (or annotate the surrounding method `?` with `@FlaggedApi(Flags.FLAG_FRP_ENFORCEMENT) to transfer requirement to caller`)"
+ errorLine1=" registerService(Context.PERSISTENT_DATA_BLOCK_SERVICE, PersistentDataBlockManager.class,"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/app/SystemServiceRegistry.java"
+ line="1067"
+ column="64"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `PERSISTENT_DATA_BLOCK_SERVICE` is a flagged API and should be inside an `if (Flags.frpEnforcement())` check (or annotate the surrounding method `?` with `@FlaggedApi(Flags.FLAG_FRP_ENFORCEMENT) to transfer requirement to caller`)"
+ errorLine1=" registerService(Context.PERSISTENT_DATA_BLOCK_SERVICE, PersistentDataBlockManager.class,"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/app/SystemServiceRegistry.java"
+ line="1067"
+ column="33"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `PERSISTENT_DATA_BLOCK_SERVICE` is a flagged API and should be inside an `if (Flags.frpEnforcement())` check (or annotate the surrounding method `createService` with `@FlaggedApi(Flags.FLAG_FRP_ENFORCEMENT) to transfer requirement to caller`)"
+ errorLine1=" IBinder b = ServiceManager.getServiceOrThrow(Context.PERSISTENT_DATA_BLOCK_SERVICE);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/app/SystemServiceRegistry.java"
+ line="1071"
+ column="70"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `PersistentDataBlockManager()` is a flagged API and should be inside an `if (Flags.frpEnforcement())` check (or annotate the surrounding method `createService` with `@FlaggedApi(Flags.FLAG_FRP_ENFORCEMENT) to transfer requirement to caller`)"
+ errorLine1=" return new PersistentDataBlockManager(persistentDataBlockService);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/app/SystemServiceRegistry.java"
+ line="1075"
+ column="28"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Class `ContextualSearchManager` is a flagged API and should be inside an `if (Flags.enableService())` check (or annotate the surrounding method `?` with `@FlaggedApi(Flags.FLAG_ENABLE_SERVICE) to transfer requirement to caller`)"
+ errorLine1=" registerService(Context.CONTEXTUAL_SEARCH_SERVICE, ContextualSearchManager.class,"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/app/SystemServiceRegistry.java"
+ line="1319"
+ column="60"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `CONTEXTUAL_SEARCH_SERVICE` is a flagged API and should be inside an `if (Flags.enableService())` check (or annotate the surrounding method `?` with `@FlaggedApi(Flags.FLAG_ENABLE_SERVICE) to transfer requirement to caller`)"
+ errorLine1=" registerService(Context.CONTEXTUAL_SEARCH_SERVICE, ContextualSearchManager.class,"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/app/SystemServiceRegistry.java"
+ line="1319"
+ column="33"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `CONTEXTUAL_SEARCH_SERVICE` is a flagged API and should be inside an `if (Flags.enableService())` check (or annotate the surrounding method `createService` with `@FlaggedApi(Flags.FLAG_ENABLE_SERVICE) to transfer requirement to caller`)"
+ errorLine1=" IBinder b = ServiceManager.getService(Context.CONTEXTUAL_SEARCH_SERVICE);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/app/SystemServiceRegistry.java"
+ line="1324"
+ column="71"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `ContextualSearchManager()` is a flagged API and should be inside an `if (Flags.enableService())` check (or annotate the surrounding method `createService` with `@FlaggedApi(Flags.FLAG_ENABLE_SERVICE) to transfer requirement to caller`)"
+ errorLine1=" return b == null ? null : new ContextualSearchManager();"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/app/SystemServiceRegistry.java"
+ line="1325"
+ column="51"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Class `DeviceStateManager` is a flagged API and should be inside an `if (Flags.deviceStatePropertyApi())` check (or annotate the surrounding method `?` with `@FlaggedApi(Flags.FLAG_DEVICE_STATE_PROPERTY_API) to transfer requirement to caller`)"
+ errorLine1=" registerService(Context.DEVICE_STATE_SERVICE, DeviceStateManager.class,"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/app/SystemServiceRegistry.java"
+ line="1564"
+ column="55"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `DeviceStateManager()` is a flagged API and should be inside an `if (Flags.deviceStatePropertyApi())` check (or annotate the surrounding method `createService` with `@FlaggedApi(Flags.FLAG_DEVICE_STATE_PROPERTY_API) to transfer requirement to caller`)"
+ errorLine1=" return new DeviceStateManager();"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/app/SystemServiceRegistry.java"
+ line="1568"
+ column="32"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Class `OnDeviceIntelligenceManager` is a flagged API and should be inside an `if (Flags.enableOnDeviceIntelligence())` check (or annotate the surrounding method `?` with `@FlaggedApi(Flags.FLAG_ENABLE_ON_DEVICE_INTELLIGENCE) to transfer requirement to caller`)"
+ errorLine1=" registerService(Context.ON_DEVICE_INTELLIGENCE_SERVICE, OnDeviceIntelligenceManager.class,"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/app/SystemServiceRegistry.java"
+ line="1638"
+ column="65"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `ON_DEVICE_INTELLIGENCE_SERVICE` is a flagged API and should be inside an `if (Flags.enableOnDeviceIntelligence())` check (or annotate the surrounding method `?` with `@FlaggedApi(Flags.FLAG_ENABLE_ON_DEVICE_INTELLIGENCE) to transfer requirement to caller`)"
+ errorLine1=" registerService(Context.ON_DEVICE_INTELLIGENCE_SERVICE, OnDeviceIntelligenceManager.class,"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/app/SystemServiceRegistry.java"
+ line="1638"
+ column="33"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `ON_DEVICE_INTELLIGENCE_SERVICE` is a flagged API and should be inside an `if (Flags.enableOnDeviceIntelligence())` check (or annotate the surrounding method `createService` with `@FlaggedApi(Flags.FLAG_ENABLE_ON_DEVICE_INTELLIGENCE) to transfer requirement to caller`)"
+ errorLine1=" Context.ON_DEVICE_INTELLIGENCE_SERVICE);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/app/SystemServiceRegistry.java"
+ line="1644"
+ column="41"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `OnDeviceIntelligenceManager()` is a flagged API and should be inside an `if (Flags.enableOnDeviceIntelligence())` check (or annotate the surrounding method `createService` with `@FlaggedApi(Flags.FLAG_ENABLE_ON_DEVICE_INTELLIGENCE) to transfer requirement to caller`)"
+ errorLine1=" return new OnDeviceIntelligenceManager(ctx.getOuterContext(), manager);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/app/SystemServiceRegistry.java"
+ line="1647"
+ column="32"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Class `E2eeContactKeysManager` is a flagged API and should be inside an `if (Flags.userKeys())` check (or annotate the surrounding method `?` with `@FlaggedApi(Flags.FLAG_USER_KEYS) to transfer requirement to caller`)"
+ errorLine1=" registerService(Context.CONTACT_KEYS_SERVICE, E2eeContactKeysManager.class,"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/app/SystemServiceRegistry.java"
+ line="1670"
+ column="55"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `CONTACT_KEYS_SERVICE` is a flagged API and should be inside an `if (Flags.userKeys())` check (or annotate the surrounding method `?` with `@FlaggedApi(Flags.FLAG_USER_KEYS) to transfer requirement to caller`)"
+ errorLine1=" registerService(Context.CONTACT_KEYS_SERVICE, E2eeContactKeysManager.class,"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/app/SystemServiceRegistry.java"
+ line="1670"
+ column="33"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `addView()` is a flagged API and should be inside an `if (Flags.enableArrowIconOnHoverWhenClickable())` check (or annotate the surrounding method `addTab` with `@FlaggedApi(Flags.FLAG_ENABLE_ARROW_ICON_ON_HOVER_WHEN_CLICKABLE) to transfer requirement to caller`)"
+ errorLine1=" mTabWidget.addView(tabIndicator);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/widget/TabHost.java"
+ line="256"
+ column="9"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="This is a flagged API and should be inside an `if (Flags.simultaneousCallingIndications())` check (or annotate the surrounding method `onSimultaneousCallingStateChanged` with `@FlaggedApi(Flags.FLAG_SIMULTANEOUS_CALLING_INDICATIONS) to transfer requirement to caller`)"
+ errorLine1=" (SimultaneousCellularCallingSupportListener) mTelephonyCallbackWeakRef.get();"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/telephony/TelephonyCallback.java"
+ line="2065"
+ column="22"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `onSimultaneousCellularCallingSubscriptionsChanged()` is a flagged API and should be inside an `if (Flags.simultaneousCallingIndications())` check (or annotate the surrounding method `onSimultaneousCallingStateChanged` with `@FlaggedApi(Flags.FLAG_SIMULTANEOUS_CALLING_INDICATIONS) to transfer requirement to caller`)"
+ errorLine1=" () -> listener.onSimultaneousCellularCallingSubscriptionsChanged("
+ errorLine2=" ^">
+ <location
+ file="frameworks/base/core/java/android/telephony/TelephonyCallback.java"
+ line="2070"
+ column="35"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Class `SatelliteManager` is a flagged API and should be inside an `if (Flags.oemEnabledSatelliteFlag())` check (or annotate the surrounding method `registerServiceWrappers` with `@FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG) to transfer requirement to caller`)"
+ errorLine1=" SatelliteManager.class,"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/TelephonyFrameworkInitializer.java"
+ line="146"
+ column="17"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `SatelliteManager()` is a flagged API and should be inside an `if (Flags.oemEnabledSatelliteFlag())` check (or annotate the surrounding method `registerServiceWrappers` with `@FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG) to transfer requirement to caller`)"
+ errorLine1=" ? new SatelliteManager(context) : null"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/TelephonyFrameworkInitializer.java"
+ line="148"
+ column="27"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="This is a flagged API and should be inside an `if (Flags.telecomResolveHiddenDependencies())` check (or annotate the surrounding method `listen` with `@FlaggedApi(Flags.FLAG_TELECOM_RESOLVE_HIDDEN_DEPENDENCIES) to transfer requirement to caller`)"
+ errorLine1=" (TelephonyRegistryManager)"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/TelephonyManager.java"
+ line="6726"
+ column="18"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `listenFromListener()` is a flagged API and should be inside an `if (Flags.telecomResolveHiddenDependencies())` check (or annotate the surrounding method `listen` with `@FlaggedApi(Flags.FLAG_TELECOM_RESOLVE_HIDDEN_DEPENDENCIES) to transfer requirement to caller`)"
+ errorLine1=" telephonyRegistry.listenFromListener(mSubId, renounceFineLocationAccess,"
+ errorLine2=" ^">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/TelephonyManager.java"
+ line="6734"
+ column="13"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="This is a flagged API and should be inside an `if (Flags.telecomResolveHiddenDependencies())` check (or annotate the surrounding method `registerTelephonyCallback` with `@FlaggedApi(Flags.FLAG_TELECOM_RESOLVE_HIDDEN_DEPENDENCIES) to transfer requirement to caller`)"
+ errorLine1=" mTelephonyRegistryMgr = (TelephonyRegistryManager)"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/TelephonyManager.java"
+ line="17689"
+ column="34"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `registerTelephonyCallback()` is a flagged API and should be inside an `if (Flags.telecomResolveHiddenDependencies())` check (or annotate the surrounding method `registerTelephonyCallback` with `@FlaggedApi(Flags.FLAG_TELECOM_RESOLVE_HIDDEN_DEPENDENCIES) to transfer requirement to caller`)"
+ errorLine1=" mTelephonyRegistryMgr.registerTelephonyCallback("
+ errorLine2=" ^">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/TelephonyManager.java"
+ line="17692"
+ column="13"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Class `TelephonyRegistryManager` is a flagged API and should be inside an `if (Flags.telecomResolveHiddenDependencies())` check (or annotate the surrounding method `unregisterTelephonyCallback` with `@FlaggedApi(Flags.FLAG_TELECOM_RESOLVE_HIDDEN_DEPENDENCIES) to transfer requirement to caller`)"
+ errorLine1=" mTelephonyRegistryMgr = mContext.getSystemService(TelephonyRegistryManager.class);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/TelephonyManager.java"
+ line="17717"
+ column="59"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `unregisterTelephonyCallback()` is a flagged API and should be inside an `if (Flags.telecomResolveHiddenDependencies())` check (or annotate the surrounding method `unregisterTelephonyCallback` with `@FlaggedApi(Flags.FLAG_TELECOM_RESOLVE_HIDDEN_DEPENDENCIES) to transfer requirement to caller`)"
+ errorLine1=" mTelephonyRegistryMgr.unregisterTelephonyCallback(mSubId, getOpPackageName(),"
+ errorLine2=" ^">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/TelephonyManager.java"
+ line="17719"
+ column="13"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Class `TelephonyRegistryManager` is a flagged API and should be inside an `if (Flags.telecomResolveHiddenDependencies())` check (or annotate the surrounding method `registerCarrierPrivilegesCallback` with `@FlaggedApi(Flags.FLAG_TELECOM_RESOLVE_HIDDEN_DEPENDENCIES) to transfer requirement to caller`)"
+ errorLine1=" mTelephonyRegistryMgr = mContext.getSystemService(TelephonyRegistryManager.class);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/TelephonyManager.java"
+ line="18688"
+ column="59"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `addCarrierPrivilegesCallback()` is a flagged API and should be inside an `if (Flags.telecomResolveHiddenDependencies())` check (or annotate the surrounding method `registerCarrierPrivilegesCallback` with `@FlaggedApi(Flags.FLAG_TELECOM_RESOLVE_HIDDEN_DEPENDENCIES) to transfer requirement to caller`)"
+ errorLine1=" mTelephonyRegistryMgr.addCarrierPrivilegesCallback(logicalSlotIndex, executor, callback);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/TelephonyManager.java"
+ line="18692"
+ column="9"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Class `TelephonyRegistryManager` is a flagged API and should be inside an `if (Flags.telecomResolveHiddenDependencies())` check (or annotate the surrounding method `unregisterCarrierPrivilegesCallback` with `@FlaggedApi(Flags.FLAG_TELECOM_RESOLVE_HIDDEN_DEPENDENCIES) to transfer requirement to caller`)"
+ errorLine1=" mTelephonyRegistryMgr = mContext.getSystemService(TelephonyRegistryManager.class);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/TelephonyManager.java"
+ line="18708"
+ column="59"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `removeCarrierPrivilegesCallback()` is a flagged API and should be inside an `if (Flags.telecomResolveHiddenDependencies())` check (or annotate the surrounding method `unregisterCarrierPrivilegesCallback` with `@FlaggedApi(Flags.FLAG_TELECOM_RESOLVE_HIDDEN_DEPENDENCIES) to transfer requirement to caller`)"
+ errorLine1=" mTelephonyRegistryMgr.removeCarrierPrivilegesCallback(callback);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/telephony/java/android/telephony/TelephonyManager.java"
+ line="18712"
+ column="9"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="This is a flagged API and should be inside an `if (Flags.simultaneousCallingIndications())` check (or annotate the surrounding method `getEventsFromCallback` with `@FlaggedApi(Flags.FLAG_SIMULTANEOUS_CALLING_INDICATIONS) to transfer requirement to caller`)"
+ errorLine1=" instanceof TelephonyCallback.SimultaneousCellularCallingSupportListener) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/telephony/TelephonyRegistryManager.java"
+ line="1241"
+ column="28"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `EVENT_SIMULTANEOUS_CELLULAR_CALLING_SUBSCRIPTIONS_CHANGED` is a flagged API and should be inside an `if (Flags.simultaneousCallingIndications())` check (or annotate the surrounding method `getEventsFromCallback` with `@FlaggedApi(Flags.FLAG_SIMULTANEOUS_CALLING_INDICATIONS) to transfer requirement to caller`)"
+ errorLine1=" TelephonyCallback.EVENT_SIMULTANEOUS_CELLULAR_CALLING_SUBSCRIPTIONS_CHANGED);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/telephony/TelephonyRegistryManager.java"
+ line="1243"
+ column="39"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `TEXT_RUN_FLAG_LEFT_EDGE` is a flagged API and should be inside an `if (Flags.letterSpacingJustification())` check (or annotate the surrounding method `calculateRunFlag` with `@FlaggedApi(Flags.FLAG_LETTER_SPACING_JUSTIFICATION) to transfer requirement to caller`)"
+ errorLine1=" return Paint.TEXT_RUN_FLAG_LEFT_EDGE | Paint.TEXT_RUN_FLAG_RIGHT_EDGE;"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/text/TextLine.java"
+ line="342"
+ column="26"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `TEXT_RUN_FLAG_RIGHT_EDGE` is a flagged API and should be inside an `if (Flags.letterSpacingJustification())` check (or annotate the surrounding method `calculateRunFlag` with `@FlaggedApi(Flags.FLAG_LETTER_SPACING_JUSTIFICATION) to transfer requirement to caller`)"
+ errorLine1=" return Paint.TEXT_RUN_FLAG_LEFT_EDGE | Paint.TEXT_RUN_FLAG_RIGHT_EDGE;"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/text/TextLine.java"
+ line="342"
+ column="58"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `TEXT_RUN_FLAG_LEFT_EDGE` is a flagged API and should be inside an `if (Flags.letterSpacingJustification())` check (or annotate the surrounding method `calculateRunFlag` with `@FlaggedApi(Flags.FLAG_LETTER_SPACING_JUSTIFICATION) to transfer requirement to caller`)"
+ errorLine1=" runFlag |= Paint.TEXT_RUN_FLAG_LEFT_EDGE;"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/text/TextLine.java"
+ line="359"
+ column="34"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `TEXT_RUN_FLAG_RIGHT_EDGE` is a flagged API and should be inside an `if (Flags.letterSpacingJustification())` check (or annotate the surrounding method `calculateRunFlag` with `@FlaggedApi(Flags.FLAG_LETTER_SPACING_JUSTIFICATION) to transfer requirement to caller`)"
+ errorLine1=" runFlag |= Paint.TEXT_RUN_FLAG_RIGHT_EDGE;"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/text/TextLine.java"
+ line="361"
+ column="34"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `TEXT_RUN_FLAG_RIGHT_EDGE` is a flagged API and should be inside an `if (Flags.letterSpacingJustification())` check (or annotate the surrounding method `calculateRunFlag` with `@FlaggedApi(Flags.FLAG_LETTER_SPACING_JUSTIFICATION) to transfer requirement to caller`)"
+ errorLine1=" runFlag |= Paint.TEXT_RUN_FLAG_RIGHT_EDGE;"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/text/TextLine.java"
+ line="366"
+ column="34"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `TEXT_RUN_FLAG_LEFT_EDGE` is a flagged API and should be inside an `if (Flags.letterSpacingJustification())` check (or annotate the surrounding method `calculateRunFlag` with `@FlaggedApi(Flags.FLAG_LETTER_SPACING_JUSTIFICATION) to transfer requirement to caller`)"
+ errorLine1=" runFlag |= Paint.TEXT_RUN_FLAG_LEFT_EDGE;"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/text/TextLine.java"
+ line="368"
+ column="34"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `TEXT_RUN_FLAG_LEFT_EDGE` is a flagged API and should be inside an `if (Flags.letterSpacingJustification())` check (or annotate the surrounding method `resolveRunFlagForSubSequence` with `@FlaggedApi(Flags.FLAG_LETTER_SPACING_JUSTIFICATION) to transfer requirement to caller`)"
+ errorLine1=" if ((runFlag & Paint.TEXT_RUN_FLAG_LEFT_EDGE) != 0) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/text/TextLine.java"
+ line="394"
+ column="30"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `TEXT_RUN_FLAG_LEFT_EDGE` is a flagged API and should be inside an `if (Flags.letterSpacingJustification())` check (or annotate the surrounding method `resolveRunFlagForSubSequence` with `@FlaggedApi(Flags.FLAG_LETTER_SPACING_JUSTIFICATION) to transfer requirement to caller`)"
+ errorLine1=" localRunFlag &= ~Paint.TEXT_RUN_FLAG_LEFT_EDGE;"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/text/TextLine.java"
+ line="398"
+ column="44"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `TEXT_RUN_FLAG_LEFT_EDGE` is a flagged API and should be inside an `if (Flags.letterSpacingJustification())` check (or annotate the surrounding method `resolveRunFlagForSubSequence` with `@FlaggedApi(Flags.FLAG_LETTER_SPACING_JUSTIFICATION) to transfer requirement to caller`)"
+ errorLine1=" localRunFlag &= ~Paint.TEXT_RUN_FLAG_LEFT_EDGE;"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/text/TextLine.java"
+ line="403"
+ column="44"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `TEXT_RUN_FLAG_RIGHT_EDGE` is a flagged API and should be inside an `if (Flags.letterSpacingJustification())` check (or annotate the surrounding method `resolveRunFlagForSubSequence` with `@FlaggedApi(Flags.FLAG_LETTER_SPACING_JUSTIFICATION) to transfer requirement to caller`)"
+ errorLine1=" if ((runFlag & Paint.TEXT_RUN_FLAG_RIGHT_EDGE) != 0) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/text/TextLine.java"
+ line="407"
+ column="30"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `TEXT_RUN_FLAG_RIGHT_EDGE` is a flagged API and should be inside an `if (Flags.letterSpacingJustification())` check (or annotate the surrounding method `resolveRunFlagForSubSequence` with `@FlaggedApi(Flags.FLAG_LETTER_SPACING_JUSTIFICATION) to transfer requirement to caller`)"
+ errorLine1=" localRunFlag &= ~Paint.TEXT_RUN_FLAG_RIGHT_EDGE;"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/text/TextLine.java"
+ line="411"
+ column="44"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `TEXT_RUN_FLAG_RIGHT_EDGE` is a flagged API and should be inside an `if (Flags.letterSpacingJustification())` check (or annotate the surrounding method `resolveRunFlagForSubSequence` with `@FlaggedApi(Flags.FLAG_LETTER_SPACING_JUSTIFICATION) to transfer requirement to caller`)"
+ errorLine1=" localRunFlag &= ~Paint.TEXT_RUN_FLAG_RIGHT_EDGE;"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/text/TextLine.java"
+ line="416"
+ column="44"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `TEXT_RUN_FLAG_LEFT_EDGE` is a flagged API and should be inside an `if (Flags.letterSpacingJustification())` check (or annotate the surrounding method `handleText` with `@FlaggedApi(Flags.FLAG_LETTER_SPACING_JUSTIFICATION) to transfer requirement to caller`)"
+ errorLine1=" if ((runFlag & Paint.TEXT_RUN_FLAG_LEFT_EDGE) == Paint.TEXT_RUN_FLAG_LEFT_EDGE) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/text/TextLine.java"
+ line="1345"
+ column="30"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `TEXT_RUN_FLAG_LEFT_EDGE` is a flagged API and should be inside an `if (Flags.letterSpacingJustification())` check (or annotate the surrounding method `handleText` with `@FlaggedApi(Flags.FLAG_LETTER_SPACING_JUSTIFICATION) to transfer requirement to caller`)"
+ errorLine1=" if ((runFlag & Paint.TEXT_RUN_FLAG_LEFT_EDGE) == Paint.TEXT_RUN_FLAG_LEFT_EDGE) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/text/TextLine.java"
+ line="1345"
+ column="64"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `TEXT_RUN_FLAG_LEFT_EDGE` is a flagged API and should be inside an `if (Flags.letterSpacingJustification())` check (or annotate the surrounding method `handleText` with `@FlaggedApi(Flags.FLAG_LETTER_SPACING_JUSTIFICATION) to transfer requirement to caller`)"
+ errorLine1=" wp.setFlags(wp.getFlags() | Paint.TEXT_RUN_FLAG_LEFT_EDGE);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/text/TextLine.java"
+ line="1346"
+ column="47"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `TEXT_RUN_FLAG_LEFT_EDGE` is a flagged API and should be inside an `if (Flags.letterSpacingJustification())` check (or annotate the surrounding method `handleText` with `@FlaggedApi(Flags.FLAG_LETTER_SPACING_JUSTIFICATION) to transfer requirement to caller`)"
+ errorLine1=" wp.setFlags(wp.getFlags() & ~Paint.TEXT_RUN_FLAG_LEFT_EDGE);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/text/TextLine.java"
+ line="1348"
+ column="48"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `TEXT_RUN_FLAG_RIGHT_EDGE` is a flagged API and should be inside an `if (Flags.letterSpacingJustification())` check (or annotate the surrounding method `handleText` with `@FlaggedApi(Flags.FLAG_LETTER_SPACING_JUSTIFICATION) to transfer requirement to caller`)"
+ errorLine1=" if ((runFlag & Paint.TEXT_RUN_FLAG_RIGHT_EDGE) == Paint.TEXT_RUN_FLAG_RIGHT_EDGE) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/text/TextLine.java"
+ line="1350"
+ column="30"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `TEXT_RUN_FLAG_RIGHT_EDGE` is a flagged API and should be inside an `if (Flags.letterSpacingJustification())` check (or annotate the surrounding method `handleText` with `@FlaggedApi(Flags.FLAG_LETTER_SPACING_JUSTIFICATION) to transfer requirement to caller`)"
+ errorLine1=" if ((runFlag & Paint.TEXT_RUN_FLAG_RIGHT_EDGE) == Paint.TEXT_RUN_FLAG_RIGHT_EDGE) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/text/TextLine.java"
+ line="1350"
+ column="65"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `TEXT_RUN_FLAG_RIGHT_EDGE` is a flagged API and should be inside an `if (Flags.letterSpacingJustification())` check (or annotate the surrounding method `handleText` with `@FlaggedApi(Flags.FLAG_LETTER_SPACING_JUSTIFICATION) to transfer requirement to caller`)"
+ errorLine1=" wp.setFlags(wp.getFlags() | Paint.TEXT_RUN_FLAG_RIGHT_EDGE);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/text/TextLine.java"
+ line="1351"
+ column="47"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `TEXT_RUN_FLAG_RIGHT_EDGE` is a flagged API and should be inside an `if (Flags.letterSpacingJustification())` check (or annotate the surrounding method `handleText` with `@FlaggedApi(Flags.FLAG_LETTER_SPACING_JUSTIFICATION) to transfer requirement to caller`)"
+ errorLine1=" wp.setFlags(wp.getFlags() & ~Paint.TEXT_RUN_FLAG_RIGHT_EDGE);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/text/TextLine.java"
+ line="1353"
+ column="48"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `CREATOR` is a flagged API and should be inside an `if (Flags.noBreakNoHyphenationSpan())` check (or annotate the surrounding method `createFromParcel` with `@FlaggedApi(Flags.FLAG_NO_BREAK_NO_HYPHENATION_SPAN) to transfer requirement to caller`)"
+ errorLine1=" span = LineBreakConfigSpan.CREATOR.createFromParcel(p);"
+ errorLine2=" ~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/text/TextUtils.java"
+ line="1023"
+ column="48"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `getFontMetricsForLocale()` is a flagged API and should be inside an `if (Flags.fixLineHeightForLocale())` check (or annotate the surrounding method `getResolvedMinimumFontMetrics` with `@FlaggedApi(Flags.FLAG_FIX_LINE_HEIGHT_FOR_LOCALE) to transfer requirement to caller`)"
+ errorLine1=" mTextPaint.getFontMetricsForLocale(mLocalePreferredFontMetrics);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/widget/TextView.java"
+ line="10860"
+ column="9"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `setMinimumFontMetrics()` is a flagged API and should be inside an `if (Flags.fixLineHeightForLocale())` check (or annotate the surrounding method `makeNewLayout` with `@FlaggedApi(Flags.FLAG_FIX_LINE_HEIGHT_FOR_LOCALE) to transfer requirement to caller`)"
+ errorLine1=" StaticLayout.Builder builder = StaticLayout.Builder.obtain(mHint, 0,"
+ errorLine2=" ^">
+ <location
+ file="frameworks/base/core/java/android/widget/TextView.java"
+ line="10965"
+ column="48"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `setUseBoundsForWidth()` is a flagged API and should be inside an `if (Flags.useBoundsForWidth())` check (or annotate the surrounding method `makeNewLayout` with `@FlaggedApi(Flags.FLAG_USE_BOUNDS_FOR_WIDTH) to transfer requirement to caller`)"
+ errorLine1=" StaticLayout.Builder builder = StaticLayout.Builder.obtain(mHint, 0,"
+ errorLine2=" ^">
+ <location
+ file="frameworks/base/core/java/android/widget/TextView.java"
+ line="10965"
+ column="48"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `setLineBreakConfig()` is a flagged API and should be inside an `if (Flags.noBreakNoHyphenationSpan())` check (or annotate the surrounding method `makeSingleLayout` with `@FlaggedApi(Flags.FLAG_NO_BREAK_NO_HYPHENATION_SPAN) to transfer requirement to caller`)"
+ errorLine1=" final DynamicLayout.Builder builder = DynamicLayout.Builder.obtain(mText, mTextPaint,"
+ errorLine2=" ^">
+ <location
+ file="frameworks/base/core/java/android/widget/TextView.java"
+ line="11029"
+ column="51"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `setMinimumFontMetrics()` is a flagged API and should be inside an `if (Flags.fixLineHeightForLocale())` check (or annotate the surrounding method `makeSingleLayout` with `@FlaggedApi(Flags.FLAG_FIX_LINE_HEIGHT_FOR_LOCALE) to transfer requirement to caller`)"
+ errorLine1=" final DynamicLayout.Builder builder = DynamicLayout.Builder.obtain(mText, mTextPaint,"
+ errorLine2=" ^">
+ <location
+ file="frameworks/base/core/java/android/widget/TextView.java"
+ line="11029"
+ column="51"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `setUseBoundsForWidth()` is a flagged API and should be inside an `if (Flags.useBoundsForWidth())` check (or annotate the surrounding method `makeSingleLayout` with `@FlaggedApi(Flags.FLAG_USE_BOUNDS_FOR_WIDTH) to transfer requirement to caller`)"
+ errorLine1=" final DynamicLayout.Builder builder = DynamicLayout.Builder.obtain(mText, mTextPaint,"
+ errorLine2=" ^">
+ <location
+ file="frameworks/base/core/java/android/widget/TextView.java"
+ line="11029"
+ column="51"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `setMinimumFontMetrics()` is a flagged API and should be inside an `if (Flags.fixLineHeightForLocale())` check (or annotate the surrounding method `makeSingleLayout` with `@FlaggedApi(Flags.FLAG_FIX_LINE_HEIGHT_FOR_LOCALE) to transfer requirement to caller`)"
+ errorLine1=" StaticLayout.Builder builder = StaticLayout.Builder.obtain(mTransformed,"
+ errorLine2=" ^">
+ <location
+ file="frameworks/base/core/java/android/widget/TextView.java"
+ line="11115"
+ column="44"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `setUseBoundsForWidth()` is a flagged API and should be inside an `if (Flags.useBoundsForWidth())` check (or annotate the surrounding method `makeSingleLayout` with `@FlaggedApi(Flags.FLAG_USE_BOUNDS_FOR_WIDTH) to transfer requirement to caller`)"
+ errorLine1=" StaticLayout.Builder builder = StaticLayout.Builder.obtain(mTransformed,"
+ errorLine2=" ^">
+ <location
+ file="frameworks/base/core/java/android/widget/TextView.java"
+ line="11115"
+ column="44"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `computeDrawingBoundingBox()` is a flagged API and should be inside an `if (Flags.useBoundsForWidth())` check (or annotate the surrounding method `desired` with `@FlaggedApi(Flags.FLAG_USE_BOUNDS_FOR_WIDTH) to transfer requirement to caller`)"
+ errorLine1=" max = Math.max(max, layout.computeDrawingBoundingBox().width());"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/widget/TextView.java"
+ line="11181"
+ column="33"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `getDrawingBoundingBox()` is a flagged API and should be inside an `if (Flags.useBoundsForWidth())` check (or annotate the surrounding method `onMeasure` with `@FlaggedApi(Flags.FLAG_USE_BOUNDS_FOR_WIDTH) to transfer requirement to caller`)"
+ errorLine1=" RectF bbox = boring.getDrawingBoundingBox();"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/widget/TextView.java"
+ line="11275"
+ column="34"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `setMinimumFontMetrics()` is a flagged API and should be inside an `if (Flags.fixLineHeightForLocale())` check (or annotate the surrounding method `suggestedSizeFitsInSpace` with `@FlaggedApi(Flags.FLAG_FIX_LINE_HEIGHT_FOR_LOCALE) to transfer requirement to caller`)"
+ errorLine1=" layoutBuilder.setAlignment(getLayoutAlignment())"
+ errorLine2=" ^">
+ <location
+ file="frameworks/base/core/java/android/widget/TextView.java"
+ line="11502"
+ column="9"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `setUseBoundsForWidth()` is a flagged API and should be inside an `if (Flags.useBoundsForWidth())` check (or annotate the surrounding method `suggestedSizeFitsInSpace` with `@FlaggedApi(Flags.FLAG_USE_BOUNDS_FOR_WIDTH) to transfer requirement to caller`)"
+ errorLine1=" layoutBuilder.setAlignment(getLayoutAlignment())"
+ errorLine2=" ^">
+ <location
+ file="frameworks/base/core/java/android/widget/TextView.java"
+ line="11502"
+ column="9"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `CONFIG_FORCE_ANALOG_FM` is a flagged API and should be inside an `if (Flags.hdRadioImproved())` check (or annotate the surrounding method `convertForceAnalogConfigFlag` with `@FlaggedApi(Flags.FLAG_HD_RADIO_IMPROVED) to transfer requirement to caller`)"
+ errorLine1=" && mTuner.isConfigFlagSupported(RadioManager.CONFIG_FORCE_ANALOG_FM)) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/hardware/radio/TunerAdapter.java"
+ line="427"
+ column="62"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `notifyTvInputSessionData()` is a flagged API and should be inside an `if (Flags.enableAdServiceFw())` check (or annotate the surrounding method `run` with `@FlaggedApi(Flags.FLAG_ENABLE_AD_SERVICE_FW) to transfer requirement to caller`)"
+ errorLine1=" mSession.getAdSession().notifyTvInputSessionData(type, data);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/media/java/android/media/tv/TvInputManager.java"
+ line="1498"
+ column="25"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `onStopPlayback()` is a flagged API and should be inside an `if (Flags.tiafVApis())` check (or annotate the surrounding method `stopPlayback` with `@FlaggedApi(Flags.FLAG_TIAF_V_APIS) to transfer requirement to caller`)"
+ errorLine1=" onStopPlayback(mode);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/media/java/android/media/tv/TvInputService.java"
+ line="2113"
+ column="13"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `onResumePlayback()` is a flagged API and should be inside an `if (Flags.tiafVApis())` check (or annotate the surrounding method `resumePlayback` with `@FlaggedApi(Flags.FLAG_TIAF_V_APIS) to transfer requirement to caller`)"
+ errorLine1=" onResumePlayback();"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/media/java/android/media/tv/TvInputService.java"
+ line="2120"
+ column="13"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `onTvAdSessionData()` is a flagged API and should be inside an `if (Flags.enableAdServiceFw())` check (or annotate the surrounding method `notifyTvAdSessionData` with `@FlaggedApi(Flags.FLAG_ENABLE_AD_SERVICE_FW) to transfer requirement to caller`)"
+ errorLine1=" onTvAdSessionData(type, data);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/media/java/android/media/tv/TvInputService.java"
+ line="2218"
+ column="13"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `onCertificate()` is a flagged API and should be inside an `if (Flags.tiafVApis())` check (or annotate the surrounding method `sendCertificate` with `@FlaggedApi(Flags.FLAG_TIAF_V_APIS) to transfer requirement to caller`)"
+ errorLine1=" onCertificate(host, port, cert);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/media/java/android/media/tv/interactive/TvInteractiveAppService.java"
+ line="1824"
+ column="13"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `onVideoFreezeUpdated()` is a flagged API and should be inside an `if (Flags.tiafVApis())` check (or annotate the surrounding method `notifyVideoFreezeUpdated` with `@FlaggedApi(Flags.FLAG_TIAF_V_APIS) to transfer requirement to caller`)"
+ errorLine1=" onVideoFreezeUpdated(isFrozen);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/media/java/android/media/tv/interactive/TvInteractiveAppService.java"
+ line="1889"
+ column="13"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `onSelectedTrackInfo()` is a flagged API and should be inside an `if (Flags.tiafVApis())` check (or annotate the surrounding method `sendSelectedTrackInfo` with `@FlaggedApi(Flags.FLAG_TIAF_V_APIS) to transfer requirement to caller`)"
+ errorLine1=" onSelectedTrackInfo(tracks);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/media/java/android/media/tv/interactive/TvInteractiveAppService.java"
+ line="1945"
+ column="13"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `onRequestSelectedTrackInfo()` is a flagged API and should be inside an `if (Flags.tiafVApis())` check (or annotate the surrounding method `onRequestSelectedTrackInfo` with `@FlaggedApi(Flags.FLAG_TIAF_V_APIS) to transfer requirement to caller`)"
+ errorLine1=" mCallback.onRequestSelectedTrackInfo(mIAppServiceId);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/media/java/android/media/tv/interactive/TvInteractiveAppView.java"
+ line="1822"
+ column="33"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `onVideoFreezeUpdated()` is a flagged API and should be inside an `if (Flags.tiafVApis())` check (or annotate the surrounding method `onVideoFreezeUpdated` with `@FlaggedApi(Flags.FLAG_TIAF_V_APIS) to transfer requirement to caller`)"
+ errorLine1=" mCallback.onVideoFreezeUpdated(mInputId, isFrozen);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/media/java/android/media/tv/TvView.java"
+ line="1779"
+ column="17"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `convertSpToDp()` is a flagged API and should be inside an `if (Flags.fontScaleConverterPublic())` check (or annotate the surrounding method `applyDimension` with `@FlaggedApi(Flags.FLAG_FONT_SCALE_CONVERTER_PUBLIC) to transfer requirement to caller`)"
+ errorLine1=" metrics.fontScaleConverter.convertSpToDp(value),"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/util/TypedValue.java"
+ line="433"
+ column="29"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `convertDpToSp()` is a flagged API and should be inside an `if (Flags.fontScaleConverterPublic())` check (or annotate the surrounding method `deriveDimension` with `@FlaggedApi(Flags.FLAG_FONT_SCALE_CONVERTER_PUBLIC) to transfer requirement to caller`)"
+ errorLine1=" return metrics.fontScaleConverter.convertDpToSp(dpValue);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/util/TypedValue.java"
+ line="479"
+ column="28"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `PERSISTENT_DEVICE_ID_DEFAULT` is a flagged API and should be inside an `if (Flags.persistentDeviceIdApi())` check (or annotate the surrounding method `grantRuntimePermission` with `@FlaggedApi(Flags.FLAG_PERSISTENT_DEVICE_ID_API) to transfer requirement to caller`)"
+ errorLine1=" VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT, userId);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/app/UiAutomationConnection.java"
+ line="367"
+ column="42"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `PERSISTENT_DEVICE_ID_DEFAULT` is a flagged API and should be inside an `if (Flags.persistentDeviceIdApi())` check (or annotate the surrounding method `revokeRuntimePermission` with `@FlaggedApi(Flags.FLAG_PERSISTENT_DEVICE_ID_API) to transfer requirement to caller`)"
+ errorLine1=" VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT, userId, null);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/app/UiAutomationConnection.java"
+ line="387"
+ column="42"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `isResumed()` is a flagged API and should be inside an `if (Flags.enableNfcMainline())` check (or annotate the surrounding method `dump` with `@FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE) to transfer requirement to caller`)"
+ errorLine1=" pw.print(pfx); pw.print("resumed: "); pw.println(mActivity.isResumed());"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/view/translation/UiTranslationController.java"
+ line="219"
+ column="58"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `COMPLIANCE_WARNING_INPUT_POWER_LIMITED` is a flagged API and should be inside an `if (Flags.enableUsbDataComplianceWarning())` check (or annotate the surrounding method `complianceWarningsToString` with `@FlaggedApi(Flags.FLAG_ENABLE_USB_DATA_COMPLIANCE_WARNING) to transfer requirement to caller`)"
+ errorLine1=" case UsbPortStatus.COMPLIANCE_WARNING_INPUT_POWER_LIMITED:"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/hardware/usb/UsbPort.java"
+ line="813"
+ column="40"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `COMPLIANCE_WARNING_MISSING_DATA_LINES` is a flagged API and should be inside an `if (Flags.enableUsbDataComplianceWarning())` check (or annotate the surrounding method `complianceWarningsToString` with `@FlaggedApi(Flags.FLAG_ENABLE_USB_DATA_COMPLIANCE_WARNING) to transfer requirement to caller`)"
+ errorLine1=" case UsbPortStatus.COMPLIANCE_WARNING_MISSING_DATA_LINES:"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/hardware/usb/UsbPort.java"
+ line="816"
+ column="40"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `COMPLIANCE_WARNING_ENUMERATION_FAIL` is a flagged API and should be inside an `if (Flags.enableUsbDataComplianceWarning())` check (or annotate the surrounding method `complianceWarningsToString` with `@FlaggedApi(Flags.FLAG_ENABLE_USB_DATA_COMPLIANCE_WARNING) to transfer requirement to caller`)"
+ errorLine1=" case UsbPortStatus.COMPLIANCE_WARNING_ENUMERATION_FAIL:"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/hardware/usb/UsbPort.java"
+ line="819"
+ column="40"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `COMPLIANCE_WARNING_FLAKY_CONNECTION` is a flagged API and should be inside an `if (Flags.enableUsbDataComplianceWarning())` check (or annotate the surrounding method `complianceWarningsToString` with `@FlaggedApi(Flags.FLAG_ENABLE_USB_DATA_COMPLIANCE_WARNING) to transfer requirement to caller`)"
+ errorLine1=" case UsbPortStatus.COMPLIANCE_WARNING_FLAKY_CONNECTION:"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/hardware/usb/UsbPort.java"
+ line="822"
+ column="40"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `COMPLIANCE_WARNING_UNRELIABLE_IO` is a flagged API and should be inside an `if (Flags.enableUsbDataComplianceWarning())` check (or annotate the surrounding method `complianceWarningsToString` with `@FlaggedApi(Flags.FLAG_ENABLE_USB_DATA_COMPLIANCE_WARNING) to transfer requirement to caller`)"
+ errorLine1=" case UsbPortStatus.COMPLIANCE_WARNING_UNRELIABLE_IO:"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/hardware/usb/UsbPort.java"
+ line="825"
+ column="40"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `USER_TYPE_PROFILE_MANAGED` is a flagged API and should be inside an `if (Flags.allowPrivateProfile())` check (or annotate the surrounding method `getDefaultUserType` with `@FlaggedApi(Flags.FLAG_ALLOW_PRIVATE_PROFILE) to transfer requirement to caller`)"
+ errorLine1=" case FLAG_MANAGED_PROFILE: return UserManager.USER_TYPE_PROFILE_MANAGED;"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/content/pm/UserInfo.java"
+ line="350"
+ column="59"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `USER_TYPE_PROFILE_MANAGED` is a flagged API and should be inside an `if (Flags.allowPrivateProfile())` check (or annotate the surrounding method `isUserTypeManagedProfile` with `@FlaggedApi(Flags.FLAG_ALLOW_PRIVATE_PROFILE) to transfer requirement to caller`)"
+ errorLine1=" return USER_TYPE_PROFILE_MANAGED.equals(userType);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/os/UserManager.java"
+ line="3063"
+ column="16"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `USER_TYPE_PROFILE_CLONE` is a flagged API and should be inside an `if (Flags.allowPrivateProfile())` check (or annotate the surrounding method `isUserTypeCloneProfile` with `@FlaggedApi(Flags.FLAG_ALLOW_PRIVATE_PROFILE) to transfer requirement to caller`)"
+ errorLine1=" return USER_TYPE_PROFILE_CLONE.equals(userType);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/os/UserManager.java"
+ line="3100"
+ column="16"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `USER_TYPE_PROFILE_PRIVATE` is a flagged API and should be inside an `if (Flags.allowPrivateProfile())` check (or annotate the surrounding method `isUserTypePrivateProfile` with `@FlaggedApi(Flags.FLAG_ALLOW_PRIVATE_PROFILE) to transfer requirement to caller`)"
+ errorLine1=" return USER_TYPE_PROFILE_PRIVATE.equals(userType);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/os/UserManager.java"
+ line="3121"
+ column="16"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `CONTENT_SENSITIVITY_AUTO` is a flagged API and should be inside an `if (Flags.sensitiveContentAppProtectionApi())` check (or annotate the surrounding method `?` with `@FlaggedApi(Flags.FLAG_SENSITIVE_CONTENT_APP_PROTECTION_API) to transfer requirement to caller`)"
+ errorLine1=" (CONTENT_SENSITIVITY_AUTO | CONTENT_SENSITIVITY_SENSITIVE"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/view/View.java"
+ line="3929"
+ column="14"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `CONTENT_SENSITIVITY_SENSITIVE` is a flagged API and should be inside an `if (Flags.sensitiveContentAppProtectionApi())` check (or annotate the surrounding method `?` with `@FlaggedApi(Flags.FLAG_SENSITIVE_CONTENT_APP_PROTECTION_API) to transfer requirement to caller`)"
+ errorLine1=" (CONTENT_SENSITIVITY_AUTO | CONTENT_SENSITIVITY_SENSITIVE"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/view/View.java"
+ line="3929"
+ column="41"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `CONTENT_SENSITIVITY_NOT_SENSITIVE` is a flagged API and should be inside an `if (Flags.sensitiveContentAppProtectionApi())` check (or annotate the surrounding method `?` with `@FlaggedApi(Flags.FLAG_SENSITIVE_CONTENT_APP_PROTECTION_API) to transfer requirement to caller`)"
+ errorLine1=" | CONTENT_SENSITIVITY_NOT_SENSITIVE) << PFLAG4_CONTENT_SENSITIVITY_SHIFT;"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/view/View.java"
+ line="3930"
+ column="23"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `REQUESTED_FRAME_RATE_CATEGORY_DEFAULT` is a flagged API and should be inside an `if (Flags.toolkitSetFrameRateReadOnly())` check (or annotate the surrounding method `?` with `@FlaggedApi(Flags.FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY) to transfer requirement to caller`)"
+ errorLine1=" private float mPreferredFrameRate = REQUESTED_FRAME_RATE_CATEGORY_DEFAULT;"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/view/View.java"
+ line="5784"
+ column="41"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `CONTENT_SENSITIVITY_AUTO` is a flagged API and should be inside an `if (Flags.sensitiveContentAppProtectionApi())` check (or annotate the surrounding method `View` with `@FlaggedApi(Flags.FLAG_SENSITIVE_CONTENT_APP_PROTECTION_API) to transfer requirement to caller`)"
+ errorLine1=" setContentSensitivity(a.getInt(attr, CONTENT_SENSITIVITY_AUTO));"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/view/View.java"
+ line="6528"
+ column="58"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `setContentSensitivity()` is a flagged API and should be inside an `if (Flags.sensitiveContentAppProtectionApi())` check (or annotate the surrounding method `View` with `@FlaggedApi(Flags.FLAG_SENSITIVE_CONTENT_APP_PROTECTION_API) to transfer requirement to caller`)"
+ errorLine1=" setContentSensitivity(a.getInt(attr, CONTENT_SENSITIVITY_AUTO));"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/view/View.java"
+ line="6528"
+ column="21"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `setPendingCredentialRequest()` is a flagged API and should be inside an `if (Flags.autofillCredmanDevIntegration())` check (or annotate the surrounding method `onProvideStructure` with `@FlaggedApi(Flags.FLAG_AUTOFILL_CREDMAN_DEV_INTEGRATION) to transfer requirement to caller`)"
+ errorLine1=" structure.setPendingCredentialRequest("
+ errorLine2=" ^">
+ <location
+ file="frameworks/base/core/java/android/view/View.java"
+ line="9665"
+ column="17"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `getPendingCredentialCallback()` is a flagged API and should be inside an `if (Flags.autofillCredmanDevIntegration())` check (or annotate the surrounding method `onGetCredentialResponse` with `@FlaggedApi(Flags.FLAG_AUTOFILL_CREDMAN_DEV_INTEGRATION) to transfer requirement to caller`)"
+ errorLine1=" if (getPendingCredentialCallback() == null) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/view/View.java"
+ line="10070"
+ column="13"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `getPendingCredentialCallback()` is a flagged API and should be inside an `if (Flags.autofillCredmanDevIntegration())` check (or annotate the surrounding method `onGetCredentialResponse` with `@FlaggedApi(Flags.FLAG_AUTOFILL_CREDMAN_DEV_INTEGRATION) to transfer requirement to caller`)"
+ errorLine1=" getPendingCredentialCallback().onResult(response);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/view/View.java"
+ line="10074"
+ column="9"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `getPendingCredentialCallback()` is a flagged API and should be inside an `if (Flags.autofillCredmanDevIntegration())` check (or annotate the surrounding method `onGetCredentialException` with `@FlaggedApi(Flags.FLAG_AUTOFILL_CREDMAN_DEV_INTEGRATION) to transfer requirement to caller`)"
+ errorLine1=" if (getPendingCredentialCallback() == null) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/view/View.java"
+ line="10081"
+ column="13"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `getPendingCredentialCallback()` is a flagged API and should be inside an `if (Flags.autofillCredmanDevIntegration())` check (or annotate the surrounding method `onGetCredentialException` with `@FlaggedApi(Flags.FLAG_AUTOFILL_CREDMAN_DEV_INTEGRATION) to transfer requirement to caller`)"
+ errorLine1=" getPendingCredentialCallback().onError(new GetCredentialException(errorType, errorMsg));"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/view/View.java"
+ line="10085"
+ column="9"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `isContentSensitive()` is a flagged API and should be inside an `if (Flags.sensitiveContentAppProtectionApi())` check (or annotate the surrounding method `updateSensitiveViewsCountIfNeeded` with `@FlaggedApi(Flags.FLAG_SENSITIVE_CONTENT_APP_PROTECTION_API) to transfer requirement to caller`)"
+ errorLine1=" if (appeared && isContentSensitive()) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/view/View.java"
+ line="10597"
+ column="25"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `setPendingCredentialRequest()` is a flagged API and should be inside an `if (Flags.autofillCredmanDevIntegration())` check (or annotate the surrounding method `populateVirtualStructure` with `@FlaggedApi(Flags.FLAG_AUTOFILL_CREDMAN_DEV_INTEGRATION) to transfer requirement to caller`)"
+ errorLine1=" structure.setPendingCredentialRequest("
+ errorLine2=" ^">
+ <location
+ file="frameworks/base/core/java/android/view/View.java"
+ line="11106"
+ column="13"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `CONTENT_SENSITIVITY_AUTO` is a flagged API and should be inside an `if (Flags.sensitiveContentAppProtectionApi())` check (or annotate the surrounding method `setAutofillHints` with `@FlaggedApi(Flags.FLAG_SENSITIVE_CONTENT_APP_PROTECTION_API) to transfer requirement to caller`)"
+ errorLine1=" if (getContentSensitivity() == CONTENT_SENSITIVITY_AUTO) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/view/View.java"
+ line="13689"
+ column="44"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `getContentSensitivity()` is a flagged API and should be inside an `if (Flags.sensitiveContentAppProtectionApi())` check (or annotate the surrounding method `setAutofillHints` with `@FlaggedApi(Flags.FLAG_SENSITIVE_CONTENT_APP_PROTECTION_API) to transfer requirement to caller`)"
+ errorLine1=" if (getContentSensitivity() == CONTENT_SENSITIVITY_AUTO) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/view/View.java"
+ line="13689"
+ column="17"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `DRAG_FLAG_GLOBAL_SAME_APPLICATION` is a flagged API and should be inside an `if (Flags.delegateUnhandledDrags())` check (or annotate the surrounding method `startDragAndDrop` with `@FlaggedApi(Flags.FLAG_DELEGATE_UNHANDLED_DRAGS) to transfer requirement to caller`)"
+ errorLine1=" if ((flags & DRAG_FLAG_GLOBAL) != 0 && ((flags & DRAG_FLAG_GLOBAL_SAME_APPLICATION) != 0)) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/view/View.java"
+ line="29019"
+ column="58"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `getIntentSender()` is a flagged API and should be inside an `if (Flags.delegateUnhandledDrags())` check (or annotate the surrounding method `hasActivityPendingIntents` with `@FlaggedApi(Flags.FLAG_DELEGATE_UNHANDLED_DRAGS) to transfer requirement to caller`)"
+ errorLine1=" if (item.getIntentSender() != null) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/view/View.java"
+ line="29187"
+ column="17"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `getIntentSender()` is a flagged API and should be inside an `if (Flags.delegateUnhandledDrags())` check (or annotate the surrounding method `hasActivityPendingIntents` with `@FlaggedApi(Flags.FLAG_DELEGATE_UNHANDLED_DRAGS) to transfer requirement to caller`)"
+ errorLine1=" final PendingIntent pi = new PendingIntent(item.getIntentSender().getTarget());"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/view/View.java"
+ line="29188"
+ column="60"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `getIntentSender()` is a flagged API and should be inside an `if (Flags.delegateUnhandledDrags())` check (or annotate the surrounding method `cleanUpPendingIntents` with `@FlaggedApi(Flags.FLAG_DELEGATE_UNHANDLED_DRAGS) to transfer requirement to caller`)"
+ errorLine1=" if (item.getIntentSender() != null) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/view/View.java"
+ line="29205"
+ column="17"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `getIntentSender()` is a flagged API and should be inside an `if (Flags.delegateUnhandledDrags())` check (or annotate the surrounding method `cleanUpPendingIntents` with `@FlaggedApi(Flags.FLAG_DELEGATE_UNHANDLED_DRAGS) to transfer requirement to caller`)"
+ errorLine1=" final PendingIntent pi = new PendingIntent(item.getIntentSender().getTarget());"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/view/View.java"
+ line="29206"
+ column="60"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `REQUESTED_FRAME_RATE_CATEGORY_NO_PREFERENCE` is a flagged API and should be inside an `if (Flags.toolkitSetFrameRateReadOnly())` check (or annotate the surrounding method `votePreferredFrameRate` with `@FlaggedApi(Flags.FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY) to transfer requirement to caller`)"
+ errorLine1=" case (int) REQUESTED_FRAME_RATE_CATEGORY_NO_PREFERENCE ->"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/view/View.java"
+ line="33991"
+ column="32"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `REQUESTED_FRAME_RATE_CATEGORY_LOW` is a flagged API and should be inside an `if (Flags.toolkitSetFrameRateReadOnly())` check (or annotate the surrounding method `votePreferredFrameRate` with `@FlaggedApi(Flags.FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY) to transfer requirement to caller`)"
+ errorLine1=" case (int) REQUESTED_FRAME_RATE_CATEGORY_LOW ->"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/view/View.java"
+ line="33994"
+ column="32"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `REQUESTED_FRAME_RATE_CATEGORY_NORMAL` is a flagged API and should be inside an `if (Flags.toolkitSetFrameRateReadOnly())` check (or annotate the surrounding method `votePreferredFrameRate` with `@FlaggedApi(Flags.FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY) to transfer requirement to caller`)"
+ errorLine1=" case (int) REQUESTED_FRAME_RATE_CATEGORY_NORMAL ->"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/view/View.java"
+ line="33997"
+ column="32"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `REQUESTED_FRAME_RATE_CATEGORY_HIGH` is a flagged API and should be inside an `if (Flags.toolkitSetFrameRateReadOnly())` check (or annotate the surrounding method `votePreferredFrameRate` with `@FlaggedApi(Flags.FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY) to transfer requirement to caller`)"
+ errorLine1=" case (int) REQUESTED_FRAME_RATE_CATEGORY_HIGH ->"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/view/View.java"
+ line="34000"
+ column="32"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `getDesiredHdrHeadroom()` is a flagged API and should be inside an `if (Flags.limitedHdr())` check (or annotate the surrounding method `enableHardwareAcceleration` with `@FlaggedApi(Flags.FLAG_LIMITED_HDR) to transfer requirement to caller`)"
+ errorLine1=" updateColorModeIfNeeded(attrs.getColorMode(), attrs.getDesiredHdrHeadroom());"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/view/ViewRootImpl.java"
+ line="2022"
+ column="63"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `getDesiredHdrHeadroom()` is a flagged API and should be inside an `if (Flags.limitedHdr())` check (or annotate the surrounding method `performTraversals` with `@FlaggedApi(Flags.FLAG_LIMITED_HDR) to transfer requirement to caller`)"
+ errorLine1=" updateColorModeIfNeeded(lp.getColorMode(), lp.getDesiredHdrHeadroom());"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/view/ViewRootImpl.java"
+ line="3748"
+ column="60"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `getFrameTimeNanos()` is a flagged API and should be inside an `if (Flags.expectedPresentationTimeApi())` check (or annotate the surrounding method `draw` with `@FlaggedApi(Flags.FLAG_EXPECTED_PRESENTATION_TIME_API) to transfer requirement to caller`)"
+ errorLine1=" mChoreographer.getFrameTimeNanos() / TimeUtils.NANOS_PER_MS;"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/view/ViewRootImpl.java"
+ line="5597"
+ column="17"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `uptimeNanos()` is a flagged API and should be inside an `if (Flags.adpfGpuReportActualWorkDuration())` check (or annotate the surrounding method `draw` with `@FlaggedApi(Flags.FLAG_ADPF_GPU_REPORT_ACTUAL_WORK_DURATION) to transfer requirement to caller`)"
+ errorLine1=" long timeNs = SystemClock.uptimeNanos();"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/view/ViewRootImpl.java"
+ line="5658"
+ column="31"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `getFrameTimeNanos()` is a flagged API and should be inside an `if (Flags.expectedPresentationTimeApi())` check (or annotate the surrounding method `run` with `@FlaggedApi(Flags.FLAG_EXPECTED_PRESENTATION_TIME_API) to transfer requirement to caller`)"
+ errorLine1=" if (doConsumeBatchedInput(mChoreographer.getFrameTimeNanos())) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/view/ViewRootImpl.java"
+ line="10449"
+ column="43"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `InputTransferToken()` is a flagged API and should be inside an `if (Flags.surfaceControlInputReceiver())` check (or annotate the surrounding method `getInputTransferToken` with `@FlaggedApi(Flags.FLAG_SURFACE_CONTROL_INPUT_RECEIVER) to transfer requirement to caller`)"
+ errorLine1=" return new InputTransferToken(inputToken);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/view/ViewRootImpl.java"
+ line="11736"
+ column="16"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `getFrameRateBoostOnTouchEnabled()` is a flagged API and should be inside an `if (Flags.toolkitSetFrameRateReadOnly())` check (or annotate the surrounding method `getFrameRateBoostOnTouchEnabled` with `@FlaggedApi(Flags.FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY) to transfer requirement to caller`)"
+ errorLine1=" return mWindowAttributes.getFrameRateBoostOnTouchEnabled();"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/view/ViewRootImpl.java"
+ line="13161"
+ column="16"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `isFrameRatePowerSavingsBalanced()` is a flagged API and should be inside an `if (Flags.toolkitSetFrameRateReadOnly())` check (or annotate the surrounding method `isFrameRatePowerSavingsBalanced` with `@FlaggedApi(Flags.FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY) to transfer requirement to caller`)"
+ errorLine1=" return mWindowAttributes.isFrameRatePowerSavingsBalanced();"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/view/ViewRootImpl.java"
+ line="13193"
+ column="20"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `POLICY_TYPE_CAMERA` is a flagged API and should be inside an `if (Flags.virtualCamera())` check (or annotate the surrounding method `hasCustomCameraSupport` with `@FlaggedApi(Flags.FLAG_VIRTUAL_CAMERA) to transfer requirement to caller`)"
+ errorLine1=" return mVirtualDevice.getDevicePolicy(POLICY_TYPE_CAMERA) == DEVICE_POLICY_CUSTOM;"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/companion/virtual/VirtualDevice.java"
+ line="200"
+ column="51"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `VirtualStylus()` is a flagged API and should be inside an `if (Flags.virtualStylus())` check (or annotate the surrounding method `createVirtualStylus` with `@FlaggedApi(Flags.FLAG_VIRTUAL_STYLUS) to transfer requirement to caller`)"
+ errorLine1=" return new VirtualStylus(config, mVirtualDevice, token);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/companion/virtual/VirtualDeviceInternal.java"
+ line="332"
+ column="20"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `VirtualCamera()` is a flagged API and should be inside an `if (Flags.virtualCamera())` check (or annotate the surrounding method `createVirtualCamera` with `@FlaggedApi(Flags.FLAG_VIRTUAL_CAMERA) to transfer requirement to caller`)"
+ errorLine1=" return new VirtualCamera(mVirtualDevice, mVirtualDevice.getVirtualCameraId(config),"
+ errorLine2=" ^">
+ <location
+ file="frameworks/base/core/java/android/companion/virtual/VirtualDeviceInternal.java"
+ line="381"
+ column="20"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `onVirtualDeviceCreated()` is a flagged API and should be inside an `if (Flags.vdmPublicApis())` check (or annotate the surrounding method `onVirtualDeviceCreated` with `@FlaggedApi(Flags.FLAG_VDM_PUBLIC_APIS) to transfer requirement to caller`)"
+ errorLine1=" mExecutor.execute(() -> mListener.onVirtualDeviceCreated(deviceId));"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/companion/virtual/VirtualDeviceManager.java"
+ line="1225"
+ column="41"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `onVirtualDeviceClosed()` is a flagged API and should be inside an `if (Flags.vdmPublicApis())` check (or annotate the surrounding method `onVirtualDeviceClosed` with `@FlaggedApi(Flags.FLAG_VDM_PUBLIC_APIS) to transfer requirement to caller`)"
+ errorLine1=" mExecutor.execute(() -> mListener.onVirtualDeviceClosed(deviceId));"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/companion/virtual/VirtualDeviceManager.java"
+ line="1235"
+ column="41"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `POLICY_TYPE_CLIPBOARD` is a flagged API and should be inside an `if (Flags.crossDeviceClipboard())` check (or annotate the surrounding method `build` with `@FlaggedApi(Flags.FLAG_CROSS_DEVICE_CLIPBOARD) to transfer requirement to caller`)"
+ errorLine1=" mDevicePolicies.delete(POLICY_TYPE_CLIPBOARD);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/companion/virtual/VirtualDeviceParams.java"
+ line="1170"
+ column="40"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `POLICY_TYPE_CAMERA` is a flagged API and should be inside an `if (Flags.virtualCamera())` check (or annotate the surrounding method `build` with `@FlaggedApi(Flags.FLAG_VIRTUAL_CAMERA) to transfer requirement to caller`)"
+ errorLine1=" mDevicePolicies.delete(POLICY_TYPE_CAMERA);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/companion/virtual/VirtualDeviceParams.java"
+ line="1174"
+ column="40"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `onSecureConnectionProvided()` is a flagged API and should be inside an `if (Flags.enableProvideWearableConnectionApi())` check (or annotate the surrounding method `provideSecureConnection` with `@FlaggedApi(Flags.FLAG_ENABLE_PROVIDE_WEARABLE_CONNECTION_API) to transfer requirement to caller`)"
+ errorLine1=" WearableSensingService.this.onSecureConnectionProvided("
+ errorLine2=" ^">
+ <location
+ file="frameworks/base/core/java/android/service/wearable/WearableSensingService.java"
+ line="142"
+ column="21"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `onDataRequestObserverRegistered()` is a flagged API and should be inside an `if (Flags.enableDataRequestObserverApi())` check (or annotate the surrounding method `registerDataRequestObserver` with `@FlaggedApi(Flags.FLAG_ENABLE_DATA_REQUEST_OBSERVER_API) to transfer requirement to caller`)"
+ errorLine1=" WearableSensingService.this.onDataRequestObserverRegistered("
+ errorLine2=" ^">
+ <location
+ file="frameworks/base/core/java/android/service/wearable/WearableSensingService.java"
+ line="193"
+ column="21"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `onDataRequestObserverUnregistered()` is a flagged API and should be inside an `if (Flags.enableDataRequestObserverApi())` check (or annotate the surrounding method `unregisterDataRequestObserver` with `@FlaggedApi(Flags.FLAG_ENABLE_DATA_REQUEST_OBSERVER_API) to transfer requirement to caller`)"
+ errorLine1=" WearableSensingService.this.onDataRequestObserverUnregistered("
+ errorLine2=" ^">
+ <location
+ file="frameworks/base/core/java/android/service/wearable/WearableSensingService.java"
+ line="217"
+ column="21"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `onStartHotwordRecognition()` is a flagged API and should be inside an `if (Flags.enableHotwordWearableSensingApi())` check (or annotate the surrounding method `startHotwordRecognition` with `@FlaggedApi(Flags.FLAG_ENABLE_HOTWORD_WEARABLE_SENSING_API) to transfer requirement to caller`)"
+ errorLine1=" WearableSensingService.this.onStartHotwordRecognition("
+ errorLine2=" ^">
+ <location
+ file="frameworks/base/core/java/android/service/wearable/WearableSensingService.java"
+ line="237"
+ column="21"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `onStopHotwordRecognition()` is a flagged API and should be inside an `if (Flags.enableHotwordWearableSensingApi())` check (or annotate the surrounding method `stopHotwordRecognition` with `@FlaggedApi(Flags.FLAG_ENABLE_HOTWORD_WEARABLE_SENSING_API) to transfer requirement to caller`)"
+ errorLine1=" WearableSensingService.this.onStopHotwordRecognition(statusConsumer);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/service/wearable/WearableSensingService.java"
+ line="250"
+ column="21"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `onValidatedByHotwordDetectionService()` is a flagged API and should be inside an `if (Flags.enableHotwordWearableSensingApi())` check (or annotate the surrounding method `onValidatedByHotwordDetectionService` with `@FlaggedApi(Flags.FLAG_ENABLE_HOTWORD_WEARABLE_SENSING_API) to transfer requirement to caller`)"
+ errorLine1=" WearableSensingService.this.onValidatedByHotwordDetectionService();"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/service/wearable/WearableSensingService.java"
+ line="256"
+ column="21"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `onStopHotwordAudioStream()` is a flagged API and should be inside an `if (Flags.enableHotwordWearableSensingApi())` check (or annotate the surrounding method `stopActiveHotwordAudio` with `@FlaggedApi(Flags.FLAG_ENABLE_HOTWORD_WEARABLE_SENSING_API) to transfer requirement to caller`)"
+ errorLine1=" WearableSensingService.this.onStopHotwordAudioStream();"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/service/wearable/WearableSensingService.java"
+ line="262"
+ column="21"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `STATUS_UNSUPPORTED_OPERATION` is a flagged API and should be inside an `if (Flags.enableUnsupportedOperationStatusCode())` check (or annotate the surrounding method `onSecureConnectionProvided` with `@FlaggedApi(Flags.FLAG_ENABLE_UNSUPPORTED_OPERATION_STATUS_CODE) to transfer requirement to caller`)"
+ errorLine1=" statusConsumer.accept(WearableSensingManager.STATUS_UNSUPPORTED_OPERATION);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/service/wearable/WearableSensingService.java"
+ line="361"
+ column="54"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `STATUS_UNSUPPORTED_OPERATION` is a flagged API and should be inside an `if (Flags.enableUnsupportedOperationStatusCode())` check (or annotate the surrounding method `onDataRequestObserverRegistered` with `@FlaggedApi(Flags.FLAG_ENABLE_UNSUPPORTED_OPERATION_STATUS_CODE) to transfer requirement to caller`)"
+ errorLine1=" statusConsumer.accept(WearableSensingManager.STATUS_UNSUPPORTED_OPERATION);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/service/wearable/WearableSensingService.java"
+ line="429"
+ column="54"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `STATUS_UNSUPPORTED_OPERATION` is a flagged API and should be inside an `if (Flags.enableUnsupportedOperationStatusCode())` check (or annotate the surrounding method `onDataRequestObserverUnregistered` with `@FlaggedApi(Flags.FLAG_ENABLE_UNSUPPORTED_OPERATION_STATUS_CODE) to transfer requirement to caller`)"
+ errorLine1=" statusConsumer.accept(WearableSensingManager.STATUS_UNSUPPORTED_OPERATION);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/service/wearable/WearableSensingService.java"
+ line="457"
+ column="54"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `REQUEST_BUNDLE_KEY` is a flagged API and should be inside an `if (Flags.enableDataRequestObserverApi())` check (or annotate the surrounding method `createDataRequester` with `@FlaggedApi(Flags.FLAG_ENABLE_DATA_REQUEST_OBSERVER_API) to transfer requirement to caller`)"
+ errorLine1=" bundle.putParcelable(WearableSensingDataRequest.REQUEST_BUNDLE_KEY, request);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/service/wearable/WearableSensingService.java"
+ line="673"
+ column="61"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `REQUEST_STATUS_CALLBACK_BUNDLE_KEY` is a flagged API and should be inside an `if (Flags.enableDataRequestObserverApi())` check (or annotate the surrounding method `createDataRequester` with `@FlaggedApi(Flags.FLAG_ENABLE_DATA_REQUEST_OBSERVER_API) to transfer requirement to caller`)"
+ errorLine1=" WearableSensingDataRequest.REQUEST_STATUS_CALLBACK_BUNDLE_KEY,"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/service/wearable/WearableSensingService.java"
+ line="682"
+ column="48"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `status` is a flagged API and should be inside an `if (Flags.updateServiceIpcWrapper())` check (or annotate the surrounding method `loadWebViewNativeLibraryFromPackage` with `@FlaggedApi(Flags.FLAG_UPDATE_SERVICE_IPC_WRAPPER) to transfer requirement to caller`)"
+ errorLine1=" if (response.status != LIBLOAD_SUCCESS"
+ errorLine2=" ~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/webkit/WebViewFactory.java"
+ line="308"
+ column="22"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `status` is a flagged API and should be inside an `if (Flags.updateServiceIpcWrapper())` check (or annotate the surrounding method `loadWebViewNativeLibraryFromPackage` with `@FlaggedApi(Flags.FLAG_UPDATE_SERVICE_IPC_WRAPPER) to transfer requirement to caller`)"
+ errorLine1=" && response.status != LIBLOAD_FAILED_WAITING_FOR_RELRO) {"
+ errorLine2=" ~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/webkit/WebViewFactory.java"
+ line="309"
+ column="29"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `status` is a flagged API and should be inside an `if (Flags.updateServiceIpcWrapper())` check (or annotate the surrounding method `loadWebViewNativeLibraryFromPackage` with `@FlaggedApi(Flags.FLAG_UPDATE_SERVICE_IPC_WRAPPER) to transfer requirement to caller`)"
+ errorLine1=" return response.status;"
+ errorLine2=" ~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/webkit/WebViewFactory.java"
+ line="310"
+ column="29"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `packageInfo` is a flagged API and should be inside an `if (Flags.updateServiceIpcWrapper())` check (or annotate the surrounding method `loadWebViewNativeLibraryFromPackage` with `@FlaggedApi(Flags.FLAG_UPDATE_SERVICE_IPC_WRAPPER) to transfer requirement to caller`)"
+ errorLine1=" if (!response.packageInfo.packageName.equals(packageName)) {"
+ errorLine2=" ~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/webkit/WebViewFactory.java"
+ line="312"
+ column="23"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `status` is a flagged API and should be inside an `if (Flags.updateServiceIpcWrapper())` check (or annotate the surrounding method `loadWebViewNativeLibraryFromPackage` with `@FlaggedApi(Flags.FLAG_UPDATE_SERVICE_IPC_WRAPPER) to transfer requirement to caller`)"
+ errorLine1=" if (loadNativeRet == LIBLOAD_SUCCESS) return response.status;"
+ errorLine2=" ~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/webkit/WebViewFactory.java"
+ line="330"
+ column="63"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `status` is a flagged API and should be inside an `if (Flags.updateServiceIpcWrapper())` check (or annotate the surrounding method `getWebViewContextAndSetProvider` with `@FlaggedApi(Flags.FLAG_UPDATE_SERVICE_IPC_WRAPPER) to transfer requirement to caller`)"
+ errorLine1=" if (response.status != LIBLOAD_SUCCESS"
+ errorLine2=" ~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/webkit/WebViewFactory.java"
+ line="459"
+ column="26"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `status` is a flagged API and should be inside an `if (Flags.updateServiceIpcWrapper())` check (or annotate the surrounding method `getWebViewContextAndSetProvider` with `@FlaggedApi(Flags.FLAG_UPDATE_SERVICE_IPC_WRAPPER) to transfer requirement to caller`)"
+ errorLine1=" && response.status != LIBLOAD_FAILED_WAITING_FOR_RELRO) {"
+ errorLine2=" ~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/webkit/WebViewFactory.java"
+ line="460"
+ column="33"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `status` is a flagged API and should be inside an `if (Flags.updateServiceIpcWrapper())` check (or annotate the surrounding method `getWebViewContextAndSetProvider` with `@FlaggedApi(Flags.FLAG_UPDATE_SERVICE_IPC_WRAPPER) to transfer requirement to caller`)"
+ errorLine1=" + getWebViewPreparationErrorReason(response.status));"
+ errorLine2=" ~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/webkit/WebViewFactory.java"
+ line="462"
+ column="69"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `packageInfo` is a flagged API and should be inside an `if (Flags.updateServiceIpcWrapper())` check (or annotate the surrounding method `getWebViewContextAndSetProvider` with `@FlaggedApi(Flags.FLAG_UPDATE_SERVICE_IPC_WRAPPER) to transfer requirement to caller`)"
+ errorLine1=" response.packageInfo.packageName);"
+ errorLine2=" ~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/webkit/WebViewFactory.java"
+ line="469"
+ column="34"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `packageInfo` is a flagged API and should be inside an `if (Flags.updateServiceIpcWrapper())` check (or annotate the surrounding method `getWebViewContextAndSetProvider` with `@FlaggedApi(Flags.FLAG_UPDATE_SERVICE_IPC_WRAPPER) to transfer requirement to caller`)"
+ errorLine1=" response.packageInfo.packageName,"
+ errorLine2=" ~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/webkit/WebViewFactory.java"
+ line="479"
+ column="30"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `packageInfo` is a flagged API and should be inside an `if (Flags.updateServiceIpcWrapper())` check (or annotate the surrounding method `getWebViewContextAndSetProvider` with `@FlaggedApi(Flags.FLAG_UPDATE_SERVICE_IPC_WRAPPER) to transfer requirement to caller`)"
+ errorLine1=" verifyPackageInfo(response.packageInfo, newPackageInfo);"
+ errorLine2=" ~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/webkit/WebViewFactory.java"
+ line="510"
+ column="40"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `InputTransferToken()` is a flagged API and should be inside an `if (Flags.surfaceControlInputReceiver())` check (or annotate the surrounding method `registerBatchedSurfaceControlInputReceiver` with `@FlaggedApi(Flags.FLAG_SURFACE_CONTROL_INPUT_RECEIVER) to transfer requirement to caller`)"
+ errorLine1=" InputTransferToken inputTransferToken = new InputTransferToken();"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/view/WindowManagerGlobal.java"
+ line="874"
+ column="49"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `onInputEvent()` is a flagged API and should be inside an `if (Flags.surfaceControlInputReceiver())` check (or annotate the surrounding method `onInputEvent` with `@FlaggedApi(Flags.FLAG_SURFACE_CONTROL_INPUT_RECEIVER) to transfer requirement to caller`)"
+ errorLine1=" boolean handled = receiver.onInputEvent(event);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/view/WindowManagerGlobal.java"
+ line="885"
+ column="55"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `InputTransferToken()` is a flagged API and should be inside an `if (Flags.surfaceControlInputReceiver())` check (or annotate the surrounding method `registerUnbatchedSurfaceControlInputReceiver` with `@FlaggedApi(Flags.FLAG_SURFACE_CONTROL_INPUT_RECEIVER) to transfer requirement to caller`)"
+ errorLine1=" InputTransferToken inputTransferToken = new InputTransferToken();"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/view/WindowManagerGlobal.java"
+ line="897"
+ column="49"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `onInputEvent()` is a flagged API and should be inside an `if (Flags.surfaceControlInputReceiver())` check (or annotate the surrounding method `onInputEvent` with `@FlaggedApi(Flags.FLAG_SURFACE_CONTROL_INPUT_RECEIVER) to transfer requirement to caller`)"
+ errorLine1=" boolean handled = receiver.onInputEvent(event);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/view/WindowManagerGlobal.java"
+ line="907"
+ column="55"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `SCREEN_RECORDING_STATE_NOT_VISIBLE` is a flagged API and should be inside an `if (Flags.screenRecordingCallbacks())` check (or annotate the surrounding method `addScreenRecordingCallback` with `@FlaggedApi(Flags.FLAG_SCREEN_RECORDING_CALLBACKS) to transfer requirement to caller`)"
+ errorLine1=" return SCREEN_RECORDING_STATE_NOT_VISIBLE;"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/view/WindowManagerImpl.java"
+ line="594"
+ column="16"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `InputTransferToken()` is a flagged API and should be inside an `if (Flags.surfaceControlInputReceiver())` check (or annotate the surrounding method `?` with `@FlaggedApi(Flags.FLAG_SURFACE_CONTROL_INPUT_RECEIVER) to transfer requirement to caller`)"
+ errorLine1=" private final InputTransferToken mInputTransferToken = new InputTransferToken();"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/view/WindowlessWindowManager.java"
+ line="94"
+ column="60"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `InputTransferToken()` is a flagged API and should be inside an `if (Flags.surfaceControlInputReceiver())` check (or annotate the surrounding method `addToDisplay` with `@FlaggedApi(Flags.FLAG_SURFACE_CONTROL_INPUT_RECEIVER) to transfer requirement to caller`)"
+ errorLine1=" state.mInputTransferToken = new InputTransferToken();"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/view/WindowlessWindowManager.java"
+ line="214"
+ column="45"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `compressToJpegR()` is a flagged API and should be inside an `if (Flags.yuvImageCompressToUltraHdr())` check (or annotate the surrounding method `compressToJpegR` with `@FlaggedApi(Flags.FLAG_YUV_IMAGE_COMPRESS_TO_ULTRA_HDR) to transfer requirement to caller`)"
+ errorLine1=" return compressToJpegR(sdr, quality, stream, emptyExif);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/graphics/java/android/graphics/YuvImage.java"
+ line="276"
+ column="16"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `allowPriorityChannels()` is a flagged API and should be inside an `if (Flags.modesApi())` check (or annotate the surrounding method `getDefaultZenPolicy` with `@FlaggedApi(Flags.FLAG_MODES_API) to transfer requirement to caller`)"
+ errorLine1=" ZenPolicy policy = new ZenPolicy.Builder()"
+ errorLine2=" ^">
+ <location
+ file="frameworks/base/core/java/android/service/notification/ZenModeConfig.java"
+ line="379"
+ column="28"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `TYPE_OTHER` is a flagged API and should be inside an `if (Flags.modesApi())` check (or annotate the surrounding method `ensureManualZenRule` with `@FlaggedApi(Flags.FLAG_MODES_API) to transfer requirement to caller`)"
+ errorLine1=" newRule.type = AutomaticZenRule.TYPE_OTHER;"
+ errorLine2=" ~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/service/notification/ZenModeConfig.java"
+ line="435"
+ column="45"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `zenDeviceEffects` is a flagged API and should be inside an `if (Flags.modesApi())` check (or annotate the surrounding method `writeRuleXml` with `@FlaggedApi(Flags.FLAG_MODES_API) to transfer requirement to caller`)"
+ errorLine1=" if (Flags.modesApi() && rule.zenDeviceEffects != null) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/service/notification/ZenModeConfig.java"
+ line="1206"
+ column="38"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `policyState()` is a flagged API and should be inside an `if (Flags.modesApi())` check (or annotate the surrounding method `toNotificationPolicy` with `@FlaggedApi(Flags.FLAG_MODES_API) to transfer requirement to caller`)"
+ errorLine1=" state = Policy.policyState(areChannelsBypassingDnd,"
+ errorLine2=" ^">
+ <location
+ file="frameworks/base/core/java/android/service/notification/ZenModeConfig.java"
+ line="1842"
+ column="21"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `getPriorityChannelsAllowed()` is a flagged API and should be inside an `if (Flags.modesApi())` check (or annotate the surrounding method `toNotificationPolicy` with `@FlaggedApi(Flags.FLAG_MODES_API) to transfer requirement to caller`)"
+ errorLine1=" manualRule.zenPolicy.getPriorityChannelsAllowed() != STATE_DISALLOW);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/service/notification/ZenModeConfig.java"
+ line="1843"
+ column="21"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `TYPE_UNKNOWN` is a flagged API and should be inside an `if (Flags.modesApi())` check (or annotate the surrounding method `?` with `@FlaggedApi(Flags.FLAG_MODES_API) to transfer requirement to caller`)"
+ errorLine1=" public int type = AutomaticZenRule.TYPE_UNKNOWN;"
+ errorLine2=" ~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/service/notification/ZenModeConfig.java"
+ line="2482"
+ column="44"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `getPriorityChannelsAllowed()` is a flagged API and should be inside an `if (Flags.modesApi())` check (or annotate the surrounding method `areAllPriorityOnlyRingerSoundsMuted` with `@FlaggedApi(Flags.FLAG_MODES_API) to transfer requirement to caller`)"
+ errorLine1=" && !(config.areChannelsBypassingDnd && policy.getPriorityChannelsAllowed()"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/service/notification/ZenModeConfig.java"
+ line="2835"
+ column="60"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `mAllowChannels` is a flagged API and should be inside an `if (Flags.modesApi())` check (or annotate the surrounding method `getAllowedChannels` with `@FlaggedApi(Flags.FLAG_MODES_API) to transfer requirement to caller`)"
+ errorLine1=" return mAllowChannels;"
+ errorLine2=" ~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/service/notification/ZenPolicy.java"
+ line="576"
+ column="16"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `mAllowChannels` is a flagged API and should be inside an `if (Flags.modesApi())` check (or annotate the surrounding method `allowChannels` with `@FlaggedApi(Flags.FLAG_MODES_API) to transfer requirement to caller`)"
+ errorLine1=" mZenPolicy.mAllowChannels = channelType;"
+ errorLine2=" ~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/service/notification/ZenPolicy.java"
+ line="1019"
+ column="24"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `FIELD_MESSAGES` is a flagged API and should be inside an `if (Flags.modesApi())` check (or annotate the surrounding method `fieldsToString` with `@FlaggedApi(Flags.FLAG_MODES_API) to transfer requirement to caller`)"
+ errorLine1=" if ((bitmask & FIELD_MESSAGES) != 0) {"
+ errorLine2=" ~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/service/notification/ZenPolicy.java"
+ line="1095"
+ column="24"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `FIELD_CALLS` is a flagged API and should be inside an `if (Flags.modesApi())` check (or annotate the surrounding method `fieldsToString` with `@FlaggedApi(Flags.FLAG_MODES_API) to transfer requirement to caller`)"
+ errorLine1=" if ((bitmask & FIELD_CALLS) != 0) {"
+ errorLine2=" ~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/service/notification/ZenPolicy.java"
+ line="1098"
+ column="24"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `FIELD_CONVERSATIONS` is a flagged API and should be inside an `if (Flags.modesApi())` check (or annotate the surrounding method `fieldsToString` with `@FlaggedApi(Flags.FLAG_MODES_API) to transfer requirement to caller`)"
+ errorLine1=" if ((bitmask & FIELD_CONVERSATIONS) != 0) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/service/notification/ZenPolicy.java"
+ line="1101"
+ column="24"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `FIELD_ALLOW_CHANNELS` is a flagged API and should be inside an `if (Flags.modesApi())` check (or annotate the surrounding method `fieldsToString` with `@FlaggedApi(Flags.FLAG_MODES_API) to transfer requirement to caller`)"
+ errorLine1=" if ((bitmask & FIELD_ALLOW_CHANNELS) != 0) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/service/notification/ZenPolicy.java"
+ line="1104"
+ column="24"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `FIELD_PRIORITY_CATEGORY_REMINDERS` is a flagged API and should be inside an `if (Flags.modesApi())` check (or annotate the surrounding method `fieldsToString` with `@FlaggedApi(Flags.FLAG_MODES_API) to transfer requirement to caller`)"
+ errorLine1=" if ((bitmask & FIELD_PRIORITY_CATEGORY_REMINDERS) != 0) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/service/notification/ZenPolicy.java"
+ line="1107"
+ column="24"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `FIELD_PRIORITY_CATEGORY_EVENTS` is a flagged API and should be inside an `if (Flags.modesApi())` check (or annotate the surrounding method `fieldsToString` with `@FlaggedApi(Flags.FLAG_MODES_API) to transfer requirement to caller`)"
+ errorLine1=" if ((bitmask & FIELD_PRIORITY_CATEGORY_EVENTS) != 0) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/service/notification/ZenPolicy.java"
+ line="1110"
+ column="24"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `FIELD_PRIORITY_CATEGORY_REPEAT_CALLERS` is a flagged API and should be inside an `if (Flags.modesApi())` check (or annotate the surrounding method `fieldsToString` with `@FlaggedApi(Flags.FLAG_MODES_API) to transfer requirement to caller`)"
+ errorLine1=" if ((bitmask & FIELD_PRIORITY_CATEGORY_REPEAT_CALLERS) != 0) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/service/notification/ZenPolicy.java"
+ line="1113"
+ column="24"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `FIELD_PRIORITY_CATEGORY_ALARMS` is a flagged API and should be inside an `if (Flags.modesApi())` check (or annotate the surrounding method `fieldsToString` with `@FlaggedApi(Flags.FLAG_MODES_API) to transfer requirement to caller`)"
+ errorLine1=" if ((bitmask & FIELD_PRIORITY_CATEGORY_ALARMS) != 0) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/service/notification/ZenPolicy.java"
+ line="1116"
+ column="24"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `FIELD_PRIORITY_CATEGORY_MEDIA` is a flagged API and should be inside an `if (Flags.modesApi())` check (or annotate the surrounding method `fieldsToString` with `@FlaggedApi(Flags.FLAG_MODES_API) to transfer requirement to caller`)"
+ errorLine1=" if ((bitmask & FIELD_PRIORITY_CATEGORY_MEDIA) != 0) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/service/notification/ZenPolicy.java"
+ line="1119"
+ column="24"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `FIELD_PRIORITY_CATEGORY_SYSTEM` is a flagged API and should be inside an `if (Flags.modesApi())` check (or annotate the surrounding method `fieldsToString` with `@FlaggedApi(Flags.FLAG_MODES_API) to transfer requirement to caller`)"
+ errorLine1=" if ((bitmask & FIELD_PRIORITY_CATEGORY_SYSTEM) != 0) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/service/notification/ZenPolicy.java"
+ line="1122"
+ column="24"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `FIELD_VISUAL_EFFECT_FULL_SCREEN_INTENT` is a flagged API and should be inside an `if (Flags.modesApi())` check (or annotate the surrounding method `fieldsToString` with `@FlaggedApi(Flags.FLAG_MODES_API) to transfer requirement to caller`)"
+ errorLine1=" if ((bitmask & FIELD_VISUAL_EFFECT_FULL_SCREEN_INTENT) != 0) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/service/notification/ZenPolicy.java"
+ line="1125"
+ column="24"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `FIELD_VISUAL_EFFECT_LIGHTS` is a flagged API and should be inside an `if (Flags.modesApi())` check (or annotate the surrounding method `fieldsToString` with `@FlaggedApi(Flags.FLAG_MODES_API) to transfer requirement to caller`)"
+ errorLine1=" if ((bitmask & FIELD_VISUAL_EFFECT_LIGHTS) != 0) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/service/notification/ZenPolicy.java"
+ line="1128"
+ column="24"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `FIELD_VISUAL_EFFECT_PEEK` is a flagged API and should be inside an `if (Flags.modesApi())` check (or annotate the surrounding method `fieldsToString` with `@FlaggedApi(Flags.FLAG_MODES_API) to transfer requirement to caller`)"
+ errorLine1=" if ((bitmask & FIELD_VISUAL_EFFECT_PEEK) != 0) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/service/notification/ZenPolicy.java"
+ line="1131"
+ column="24"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `FIELD_VISUAL_EFFECT_STATUS_BAR` is a flagged API and should be inside an `if (Flags.modesApi())` check (or annotate the surrounding method `fieldsToString` with `@FlaggedApi(Flags.FLAG_MODES_API) to transfer requirement to caller`)"
+ errorLine1=" if ((bitmask & FIELD_VISUAL_EFFECT_STATUS_BAR) != 0) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/service/notification/ZenPolicy.java"
+ line="1134"
+ column="24"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `FIELD_VISUAL_EFFECT_BADGE` is a flagged API and should be inside an `if (Flags.modesApi())` check (or annotate the surrounding method `fieldsToString` with `@FlaggedApi(Flags.FLAG_MODES_API) to transfer requirement to caller`)"
+ errorLine1=" if ((bitmask & FIELD_VISUAL_EFFECT_BADGE) != 0) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/service/notification/ZenPolicy.java"
+ line="1137"
+ column="24"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `FIELD_VISUAL_EFFECT_AMBIENT` is a flagged API and should be inside an `if (Flags.modesApi())` check (or annotate the surrounding method `fieldsToString` with `@FlaggedApi(Flags.FLAG_MODES_API) to transfer requirement to caller`)"
+ errorLine1=" if ((bitmask & FIELD_VISUAL_EFFECT_AMBIENT) != 0) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/service/notification/ZenPolicy.java"
+ line="1140"
+ column="24"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `FIELD_VISUAL_EFFECT_NOTIFICATION_LIST` is a flagged API and should be inside an `if (Flags.modesApi())` check (or annotate the surrounding method `fieldsToString` with `@FlaggedApi(Flags.FLAG_MODES_API) to transfer requirement to caller`)"
+ errorLine1=" if ((bitmask & FIELD_VISUAL_EFFECT_NOTIFICATION_LIST) != 0) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/core/java/android/service/notification/ZenPolicy.java"
+ line="1143"
+ column="24"/>
+ </issue>
+
</issues>
\ No newline at end of file
diff --git a/location/Android.bp b/location/Android.bp
index 5ba35ac..e864689 100644
--- a/location/Android.bp
+++ b/location/Android.bp
@@ -39,6 +39,9 @@
"frameworks/base/core/java",
],
},
+ lint: {
+ baseline_filename: "lint-baseline.xml",
+ },
}
platform_compat_config {
diff --git a/location/lint-baseline.xml b/location/lint-baseline.xml
new file mode 100644
index 0000000..a5a2e25
--- /dev/null
+++ b/location/lint-baseline.xml
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<issues format="6" by="lint 8.4.0-alpha08" type="baseline" client="" dependencies="true" name="" variant="all" version="8.4.0-alpha08">
+
+ <issue
+ id="FlaggedApi"
+ message="Method `Builder()` is a flagged API and should be inside an `if (Flags.newGeocoder())` check (or annotate the surrounding method `getFromLocation` with `@FlaggedApi(Flags.FLAG_NEW_GEOCODER) to transfer requirement to caller`)"
+ errorLine1=" new ReverseGeocodeRequest.Builder("
+ errorLine2=" ^">
+ <location
+ file="frameworks/base/location/java/android/location/Geocoder.java"
+ line="170"
+ column="17"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `setCallingAttributionTag()` is a flagged API and should be inside an `if (Flags.newGeocoder())` check (or annotate the surrounding method `getFromLocation` with `@FlaggedApi(Flags.FLAG_NEW_GEOCODER) to transfer requirement to caller`)"
+ errorLine1=" b.setCallingAttributionTag(mContext.getAttributionTag());"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/location/java/android/location/Geocoder.java"
+ line="178"
+ column="13"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `build()` is a flagged API and should be inside an `if (Flags.newGeocoder())` check (or annotate the surrounding method `getFromLocation` with `@FlaggedApi(Flags.FLAG_NEW_GEOCODER) to transfer requirement to caller`)"
+ errorLine1=" mService.reverseGeocode(b.build(), new GeocodeCallbackImpl(listener));"
+ errorLine2=" ~~~~~~~~~">
+ <location
+ file="frameworks/base/location/java/android/location/Geocoder.java"
+ line="181"
+ column="37"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `Builder()` is a flagged API and should be inside an `if (Flags.newGeocoder())` check (or annotate the surrounding method `getFromLocationName` with `@FlaggedApi(Flags.FLAG_NEW_GEOCODER) to transfer requirement to caller`)"
+ errorLine1=" new ForwardGeocodeRequest.Builder("
+ errorLine2=" ^">
+ <location
+ file="frameworks/base/location/java/android/location/Geocoder.java"
+ line="322"
+ column="17"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `setCallingAttributionTag()` is a flagged API and should be inside an `if (Flags.newGeocoder())` check (or annotate the surrounding method `getFromLocationName` with `@FlaggedApi(Flags.FLAG_NEW_GEOCODER) to transfer requirement to caller`)"
+ errorLine1=" b.setCallingAttributionTag(mContext.getAttributionTag());"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/location/java/android/location/Geocoder.java"
+ line="333"
+ column="13"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `build()` is a flagged API and should be inside an `if (Flags.newGeocoder())` check (or annotate the surrounding method `getFromLocationName` with `@FlaggedApi(Flags.FLAG_NEW_GEOCODER) to transfer requirement to caller`)"
+ errorLine1=" mService.forwardGeocode(b.build(), new GeocodeCallbackImpl(listener));"
+ errorLine2=" ~~~~~~~~~">
+ <location
+ file="frameworks/base/location/java/android/location/Geocoder.java"
+ line="336"
+ column="37"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `getWorkSource()` is a flagged API and should be inside an `if (Flags.gnssApiMeasurementRequestWorkSource())` check (or annotate the surrounding method `Builder` with `@FlaggedApi(Flags.FLAG_GNSS_API_MEASUREMENT_REQUEST_WORK_SOURCE) to transfer requirement to caller`)"
+ errorLine1=" mWorkSource = request.getWorkSource();"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/location/java/android/location/GnssMeasurementRequest.java"
+ line="234"
+ column="27"/>
+ </issue>
+
+</issues>
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 386a606c..e134c23 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -4069,8 +4069,10 @@
private boolean delegateSoundEffectToVdm(@SystemSoundEffect int effectType) {
if (hasCustomPolicyVirtualDeviceContext()) {
VirtualDeviceManager vdm = getVirtualDeviceManager();
- vdm.playSoundEffect(mOriginalContextDeviceId, effectType);
- return true;
+ if (vdm != null) {
+ vdm.playSoundEffect(mOriginalContextDeviceId, effectType);
+ return true;
+ }
}
return false;
}
diff --git a/media/java/android/media/MediaRoute2Info.java b/media/java/android/media/MediaRoute2Info.java
index 0589c0f12..e048d5c 100644
--- a/media/java/android/media/MediaRoute2Info.java
+++ b/media/java/android/media/MediaRoute2Info.java
@@ -26,6 +26,7 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SuppressLint;
import android.annotation.TestApi;
import android.net.Uri;
import android.os.Bundle;
@@ -813,6 +814,34 @@
|| mAllowedPackages.contains(packageName);
}
+ /**
+ * Returns whether this route's type can only be published by the system route provider.
+ *
+ * @see #isSystemRoute()
+ * @hide
+ */
+ // The default case catches all other types.
+ @SuppressLint("SwitchIntDef")
+ public boolean isSystemRouteType() {
+ return switch (mType) {
+ case TYPE_BUILTIN_SPEAKER,
+ TYPE_BLUETOOTH_A2DP,
+ TYPE_DOCK,
+ TYPE_BLE_HEADSET,
+ TYPE_HEARING_AID,
+ TYPE_HDMI,
+ TYPE_HDMI_ARC,
+ TYPE_HDMI_EARC,
+ TYPE_USB_ACCESSORY,
+ TYPE_USB_DEVICE,
+ TYPE_USB_HEADSET,
+ TYPE_WIRED_HEADPHONES,
+ TYPE_WIRED_HEADSET ->
+ true;
+ default -> false;
+ };
+ }
+
/** Returns the route suitability status. */
@SuitabilityStatus
@FlaggedApi(FLAG_ENABLE_BUILT_IN_SPEAKER_ROUTE_SUITABILITY_STATUSES)
diff --git a/media/java/android/media/MediaRoute2ProviderService.java b/media/java/android/media/MediaRoute2ProviderService.java
index cce3d4f..a14f1fd 100644
--- a/media/java/android/media/MediaRoute2ProviderService.java
+++ b/media/java/android/media/MediaRoute2ProviderService.java
@@ -475,9 +475,25 @@
*/
public final void notifyRoutes(@NonNull Collection<MediaRoute2Info> routes) {
Objects.requireNonNull(routes, "routes must not be null");
- mProviderInfo = new MediaRoute2ProviderInfo.Builder()
- .addRoutes(routes)
- .build();
+ List<MediaRoute2Info> sanitizedRoutes = new ArrayList<>(routes.size());
+
+ for (MediaRoute2Info route : routes) {
+ if (route.isSystemRouteType()) {
+ Log.w(
+ TAG,
+ "Attempting to add a system route type from a non-system route "
+ + "provider. Overriding type to TYPE_UNKNOWN. Route: "
+ + route);
+ sanitizedRoutes.add(
+ new MediaRoute2Info.Builder(route)
+ .setType(MediaRoute2Info.TYPE_UNKNOWN)
+ .build());
+ } else {
+ sanitizedRoutes.add(route);
+ }
+ }
+
+ mProviderInfo = new MediaRoute2ProviderInfo.Builder().addRoutes(sanitizedRoutes).build();
schedulePublishState();
}
diff --git a/nfc/lint-baseline.xml b/nfc/lint-baseline.xml
index 1dfdd29..dd7b03d 100644
--- a/nfc/lint-baseline.xml
+++ b/nfc/lint-baseline.xml
@@ -210,4 +210,81 @@
column="23"/>
</issue>
+ <issue
+ id="FlaggedApi"
+ message="Method `NfcOemExtension()` is a flagged API and should be inside an `if (Flags.nfcOemExtension())` check (or annotate the surrounding method `NfcAdapter` with `@FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION) to transfer requirement to caller`)"
+ errorLine1=" mNfcOemExtension = new NfcOemExtension(mContext, this);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/nfc/java/android/nfc/NfcAdapter.java"
+ line="909"
+ column="28"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `FLAG_SET_DEFAULT_TECH` is a flagged API and should be inside an `if (Flags.nfcSetDefaultDiscTech())` check (or annotate the surrounding method `setDiscoveryTechnology` with `@FlaggedApi(Flags.FLAG_NFC_SET_DEFAULT_DISC_TECH) to transfer requirement to caller`)"
+ errorLine1=" && ((pollTechnology & FLAG_SET_DEFAULT_TECH) == FLAG_SET_DEFAULT_TECH"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/nfc/java/android/nfc/NfcAdapter.java"
+ line="1917"
+ column="39"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `FLAG_SET_DEFAULT_TECH` is a flagged API and should be inside an `if (Flags.nfcSetDefaultDiscTech())` check (or annotate the surrounding method `setDiscoveryTechnology` with `@FlaggedApi(Flags.FLAG_NFC_SET_DEFAULT_DISC_TECH) to transfer requirement to caller`)"
+ errorLine1=" && ((pollTechnology & FLAG_SET_DEFAULT_TECH) == FLAG_SET_DEFAULT_TECH"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/nfc/java/android/nfc/NfcAdapter.java"
+ line="1917"
+ column="65"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `FLAG_SET_DEFAULT_TECH` is a flagged API and should be inside an `if (Flags.nfcSetDefaultDiscTech())` check (or annotate the surrounding method `setDiscoveryTechnology` with `@FlaggedApi(Flags.FLAG_NFC_SET_DEFAULT_DISC_TECH) to transfer requirement to caller`)"
+ errorLine1=" || (listenTechnology & FLAG_SET_DEFAULT_TECH) == FLAG_SET_DEFAULT_TECH)) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/nfc/java/android/nfc/NfcAdapter.java"
+ line="1918"
+ column="40"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Field `FLAG_SET_DEFAULT_TECH` is a flagged API and should be inside an `if (Flags.nfcSetDefaultDiscTech())` check (or annotate the surrounding method `setDiscoveryTechnology` with `@FlaggedApi(Flags.FLAG_NFC_SET_DEFAULT_DISC_TECH) to transfer requirement to caller`)"
+ errorLine1=" || (listenTechnology & FLAG_SET_DEFAULT_TECH) == FLAG_SET_DEFAULT_TECH)) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/nfc/java/android/nfc/NfcAdapter.java"
+ line="1918"
+ column="66"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `onVendorNciResponse()` is a flagged API and should be inside an `if (Flags.nfcVendorCmd())` check (or annotate the surrounding method `onVendorResponseReceived` with `@FlaggedApi(Flags.FLAG_NFC_VENDOR_CMD) to transfer requirement to caller`)"
+ errorLine1=" executor.execute(() -> callback.onVendorNciResponse(gid, oid, payload));"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/nfc/java/android/nfc/NfcVendorNciCallbackListener.java"
+ line="88"
+ column="44"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `onVendorNciNotification()` is a flagged API and should be inside an `if (Flags.nfcVendorCmd())` check (or annotate the surrounding method `onVendorNotificationReceived` with `@FlaggedApi(Flags.FLAG_NFC_VENDOR_CMD) to transfer requirement to caller`)"
+ errorLine1=" executor.execute(() -> callback.onVendorNciNotification(gid, oid, payload));"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/nfc/java/android/nfc/NfcVendorNciCallbackListener.java"
+ line="106"
+ column="44"/>
+ </issue>
+
</issues>
\ No newline at end of file
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionAssociationActivity.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionAssociationActivity.java
index f98908c..66ab81b 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionAssociationActivity.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionAssociationActivity.java
@@ -16,10 +16,7 @@
package com.android.companiondevicemanager;
-import static android.companion.CompanionDeviceManager.REASON_CANCELED;
-import static android.companion.CompanionDeviceManager.REASON_DISCOVERY_TIMEOUT;
-import static android.companion.CompanionDeviceManager.REASON_INTERNAL_ERROR;
-import static android.companion.CompanionDeviceManager.REASON_USER_REJECTED;
+import static android.companion.CompanionDeviceManager.RESULT_CANCELED;
import static android.companion.CompanionDeviceManager.RESULT_DISCOVERY_TIMEOUT;
import static android.companion.CompanionDeviceManager.RESULT_INTERNAL_ERROR;
import static android.companion.CompanionDeviceManager.RESULT_USER_REJECTED;
@@ -27,6 +24,8 @@
import static com.android.companiondevicemanager.CompanionDeviceDiscoveryService.DiscoveryState;
import static com.android.companiondevicemanager.CompanionDeviceDiscoveryService.DiscoveryState.FINISHED_TIMEOUT;
+import static com.android.companiondevicemanager.CompanionDeviceDiscoveryService.LOCK;
+import static com.android.companiondevicemanager.CompanionDeviceDiscoveryService.sDiscoveryStarted;
import static com.android.companiondevicemanager.CompanionDeviceResources.PROFILE_ICONS;
import static com.android.companiondevicemanager.CompanionDeviceResources.PROFILE_NAMES;
import static com.android.companiondevicemanager.CompanionDeviceResources.PROFILE_PERMISSIONS;
@@ -232,8 +231,7 @@
boolean forCancelDialog = intent.getBooleanExtra(EXTRA_FORCE_CANCEL_CONFIRMATION, false);
if (forCancelDialog) {
Slog.i(TAG, "Cancelling the user confirmation");
- cancel(/* discoveryTimeOut */ false, /* userRejected */ false,
- /* internalError */ false);
+ cancel(RESULT_CANCELED);
return;
}
@@ -241,8 +239,14 @@
// yet). We can only "process" one request at a time.
final IAssociationRequestCallback appCallback = IAssociationRequestCallback.Stub
.asInterface(intent.getExtras().getBinder(EXTRA_APPLICATION_CALLBACK));
+
+ if (appCallback == null) {
+ return;
+ }
+ Slog.e(TAG, "More than one AssociationRequests are processing.");
+
try {
- requireNonNull(appCallback).onFailure("Busy.");
+ appCallback.onFailure(RESULT_INTERNAL_ERROR);
} catch (RemoteException ignore) {
}
}
@@ -253,8 +257,7 @@
// TODO: handle config changes without cancelling.
if (!isDone()) {
- cancel(/* discoveryTimeOut */ false,
- /* userRejected */ false, /* internalError */ false); // will finish()
+ cancel(RESULT_CANCELED); // will finish()
}
}
@@ -326,8 +329,11 @@
private void onDiscoveryStateChanged(DiscoveryState newState) {
if (newState == FINISHED_TIMEOUT
&& CompanionDeviceDiscoveryService.getScanResult().getValue().isEmpty()) {
- cancel(/* discoveryTimeOut */ true,
- /* userRejected */ false, /* internalError */ false);
+ synchronized (LOCK) {
+ if (sDiscoveryStarted) {
+ cancel(RESULT_DISCOVERY_TIMEOUT);
+ }
+ }
}
}
@@ -365,7 +371,7 @@
mCdmServiceReceiver.send(RESULT_CODE_ASSOCIATION_APPROVED, data);
}
- private void cancel(boolean discoveryTimeout, boolean userRejected, boolean internalError) {
+ private void cancel(int failureCode) {
if (isDone()) {
Slog.w(TAG, "Already done: " + (mApproved ? "Approved" : "Cancelled"));
return;
@@ -373,35 +379,19 @@
mCancelled = true;
// Stop discovery service if it was used.
- if (!mRequest.isSelfManaged() || discoveryTimeout) {
+ if (!mRequest.isSelfManaged()) {
CompanionDeviceDiscoveryService.stop(this);
}
- final String cancelReason;
- final int resultCode;
- if (userRejected) {
- cancelReason = REASON_USER_REJECTED;
- resultCode = RESULT_USER_REJECTED;
- } else if (discoveryTimeout) {
- cancelReason = REASON_DISCOVERY_TIMEOUT;
- resultCode = RESULT_DISCOVERY_TIMEOUT;
- } else if (internalError) {
- cancelReason = REASON_INTERNAL_ERROR;
- resultCode = RESULT_INTERNAL_ERROR;
- } else {
- cancelReason = REASON_CANCELED;
- resultCode = CompanionDeviceManager.RESULT_CANCELED;
- }
-
// First send callback to the app directly...
try {
- Slog.i(TAG, "Sending onFailure to app due to reason=" + cancelReason);
- mAppCallback.onFailure(cancelReason);
+ Slog.i(TAG, "Sending onFailure to app due to failureCode=" + failureCode);
+ mAppCallback.onFailure(failureCode);
} catch (RemoteException ignore) {
}
// ... then set result and finish ("sending" onActivityResult()).
- setResultAndFinish(null, resultCode);
+ setResultAndFinish(null, failureCode);
}
private void setResultAndFinish(@Nullable AssociationInfo association, int resultCode) {
@@ -446,8 +436,7 @@
}
} catch (PackageManager.NameNotFoundException e) {
Slog.e(TAG, "Package u" + userId + "/" + packageName + " not found.");
- cancel(/* discoveryTimeout */ false,
- /* userRejected */ false, /* internalError */ true);
+ cancel(RESULT_INTERNAL_ERROR);
return;
}
@@ -568,6 +557,8 @@
updateSingleDeviceUi();
+ if (mRequest.isSkipPrompt()) return;
+
mSummary.setVisibility(View.VISIBLE);
mButtonAllow.setVisibility(View.VISIBLE);
mButtonNotAllow.setVisibility(View.VISIBLE);
@@ -629,7 +620,7 @@
// Disable the button, to prevent more clicks.
v.setEnabled(false);
- cancel(/* discoveryTimeout */ false, /* userRejected */ true, /* internalError */ false);
+ cancel(RESULT_USER_REJECTED);
}
private void onShowHelperDialog(View view) {
@@ -755,7 +746,7 @@
@Override
public void onShowHelperDialogFailed() {
- cancel(/* discoveryTimeout */ false, /* userRejected */ false, /* internalError */ true);
+ cancel(RESULT_INTERNAL_ERROR);
}
@Override
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java
index e809433..6c1bc4e 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java
@@ -90,9 +90,6 @@
new MutableLiveData<>(Collections.emptyList());
private static MutableLiveData<DiscoveryState> sStateLiveData =
new MutableLiveData<>(DiscoveryState.NOT_STARTED);
- private static final Object LOCK = new Object();
- @GuardedBy("LOCK")
- private static boolean sDiscoveryStarted = false;
private BluetoothManager mBtManager;
private BluetoothAdapter mBtAdapter;
@@ -109,6 +106,10 @@
private boolean mStopAfterFirstMatch;
+ static final Object LOCK = new Object();
+ @GuardedBy("LOCK")
+ static boolean sDiscoveryStarted = false;
+
/**
* A state enum for devices' discovery.
*/
@@ -127,6 +128,7 @@
return false;
}
}
+ sScanResultsLiveData.setValue(Collections.emptyList());
requireNonNull(associationRequest);
final Intent intent = new Intent(context, CompanionDeviceDiscoveryService.class);
intent.setAction(ACTION_START_DISCOVERY);
@@ -192,7 +194,6 @@
sDiscoveryStarted = true;
}
mStopAfterFirstMatch = request.isSingleDevice();
- sScanResultsLiveData.setValue(Collections.emptyList());
sStateLiveData.setValue(DiscoveryState.IN_PROGRESS);
final List<DeviceFilter<?>> allFilters = request.getDeviceFilters();
diff --git a/packages/CtsShim/apk/riscv64/CtsShim.apk b/packages/CtsShim/apk/riscv64/CtsShim.apk
index af306a5..5ab190d 100644
--- a/packages/CtsShim/apk/riscv64/CtsShim.apk
+++ b/packages/CtsShim/apk/riscv64/CtsShim.apk
Binary files differ
diff --git a/packages/CtsShim/apk/riscv64/CtsShimPriv.apk b/packages/CtsShim/apk/riscv64/CtsShimPriv.apk
index 9a9997d..441f86f 100644
--- a/packages/CtsShim/apk/riscv64/CtsShimPriv.apk
+++ b/packages/CtsShim/apk/riscv64/CtsShimPriv.apk
Binary files differ
diff --git a/packages/SettingsLib/OWNERS b/packages/SettingsLib/OWNERS
index 5966c9f..62ed66c 100644
--- a/packages/SettingsLib/OWNERS
+++ b/packages/SettingsLib/OWNERS
@@ -11,3 +11,6 @@
# Exempt resource files (because they are in a flat directory and too hard to manage via OWNERS)
per-file *.xml=*
+
+# Notification-related utilities
+per-file */notification/* = file:/packages/SystemUI/src/com/android/systemui/statusbar/notification/OWNERS
diff --git a/packages/SettingsLib/Spa/testutils/src/com/android/settingslib/spa/testutils/ComposeContentTestRuleExt.kt b/packages/SettingsLib/Spa/testutils/src/com/android/settingslib/spa/testutils/ComposeContentTestRuleExt.kt
index 0436fc2..53d4531 100644
--- a/packages/SettingsLib/Spa/testutils/src/com/android/settingslib/spa/testutils/ComposeContentTestRuleExt.kt
+++ b/packages/SettingsLib/Spa/testutils/src/com/android/settingslib/spa/testutils/ComposeContentTestRuleExt.kt
@@ -17,6 +17,7 @@
package com.android.settingslib.spa.testutils
import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.safeDrawingPadding
import androidx.compose.foundation.layout.sizeIn
import androidx.compose.material3.Surface
import androidx.compose.runtime.Composable
@@ -75,7 +76,7 @@
setContent {
SettingsTheme {
Surface {
- Box {
+ Box(Modifier.safeDrawingPadding()) {
Box(
Modifier
.sizeIn(maxWidth = parentMaxWidth, maxHeight = parentMaxHeight)
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsGlobalBoolean.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsGlobalBoolean.kt
index 5d67f57..42528695 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsGlobalBoolean.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsGlobalBoolean.kt
@@ -21,16 +21,25 @@
import android.provider.Settings
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
+import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.conflate
import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
-fun Context.settingsGlobalBoolean(name: String, defaultValue: Boolean = false):
- ReadWriteProperty<Any?, Boolean> = SettingsGlobalBooleanDelegate(this, name, defaultValue)
+fun Context.settingsGlobalBoolean(
+ name: String,
+ defaultValue: Boolean = false,
+): ReadWriteProperty<Any?, Boolean> = SettingsGlobalBooleanDelegate(this, name, defaultValue)
fun Context.settingsGlobalBooleanFlow(name: String, defaultValue: Boolean = false): Flow<Boolean> {
val value by settingsGlobalBoolean(name, defaultValue)
- return settingsGlobalChangeFlow(name).map { value }.distinctUntilChanged()
+ return settingsGlobalChangeFlow(name)
+ .map { value }
+ .distinctUntilChanged()
+ .conflate()
+ .flowOn(Dispatchers.Default)
}
private class SettingsGlobalBooleanDelegate(
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsSecureBoolean.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsSecureBoolean.kt
index 25090a4..d5f4ec2 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsSecureBoolean.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsSecureBoolean.kt
@@ -22,16 +22,25 @@
import com.android.settingslib.spaprivileged.database.contentChangeFlow
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
+import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.conflate
import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
-fun Context.settingsSecureBoolean(name: String, defaultValue: Boolean = false):
- ReadWriteProperty<Any?, Boolean> = SettingsSecureBooleanDelegate(this, name, defaultValue)
+fun Context.settingsSecureBoolean(
+ name: String,
+ defaultValue: Boolean = false,
+): ReadWriteProperty<Any?, Boolean> = SettingsSecureBooleanDelegate(this, name, defaultValue)
fun Context.settingsSecureBooleanFlow(name: String, defaultValue: Boolean = false): Flow<Boolean> {
val value by settingsSecureBoolean(name, defaultValue)
- return contentChangeFlow(Settings.Secure.getUriFor(name)).map { value }.distinctUntilChanged()
+ return contentChangeFlow(Settings.Secure.getUriFor(name))
+ .map { value }
+ .distinctUntilChanged()
+ .conflate()
+ .flowOn(Dispatchers.Default)
}
private class SettingsSecureBooleanDelegate(
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsSecureString.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsSecureString.kt
new file mode 100644
index 0000000..a706308
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsSecureString.kt
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.spaprivileged.settingsprovider
+
+import android.content.ContentResolver
+import android.content.Context
+import android.provider.Settings
+import com.android.settingslib.spaprivileged.database.contentChangeFlow
+import kotlin.properties.ReadWriteProperty
+import kotlin.reflect.KProperty
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.conflate
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.flowOn
+import kotlinx.coroutines.flow.map
+
+fun Context.settingsSecureString(
+ name: String,
+ defaultValue: String = ""
+): ReadWriteProperty<Any?, String> = SettingsSecureStringDelegate(this, name, defaultValue)
+
+fun Context.settingsSecureStringFlow(name: String, defaultValue: String = ""): Flow<String> {
+ val value by settingsSecureString(name, defaultValue)
+ return contentChangeFlow(Settings.Secure.getUriFor(name))
+ .map { value }
+ .distinctUntilChanged()
+ .conflate()
+ .flowOn(Dispatchers.Default)
+}
+
+private class SettingsSecureStringDelegate(
+ context: Context,
+ private val name: String,
+ private val defaultValue: String = "",
+) : ReadWriteProperty<Any?, String> {
+
+ private val contentResolver: ContentResolver = context.contentResolver
+
+ override fun getValue(thisRef: Any?, property: KProperty<*>): String =
+ Settings.Secure.getString(contentResolver, name) ?: defaultValue
+
+ override fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
+ Settings.Secure.putString(contentResolver, name, value)
+ }
+}
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppList.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppList.kt
index 2a04424..627b248 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppList.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppList.kt
@@ -19,6 +19,7 @@
import android.content.Context
import android.content.pm.ApplicationInfo
import android.os.Process
+import android.os.UserHandle
import androidx.compose.runtime.Composable
import com.android.settingslib.spa.framework.common.SettingsEntryBuilder
import com.android.settingslib.spa.framework.common.SettingsPageProvider
@@ -88,7 +89,8 @@
*
* If true, the app gets all permissions, so the permission toggle always not changeable.
*/
-fun AppRecord.isSystemOrRootUid(): Boolean = app.uid in listOf(Process.SYSTEM_UID, Process.ROOT_UID)
+fun AppRecord.isSystemOrRootUid(): Boolean =
+ UserHandle.getAppId(app.uid) in listOf(Process.SYSTEM_UID, Process.ROOT_UID)
/**
* Gets whether the permission on / off is changeable for the given app.
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsSecureStringTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsSecureStringTest.kt
new file mode 100644
index 0000000..e3d182b
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsSecureStringTest.kt
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.spaprivileged.settingsprovider
+
+import android.content.Context
+import android.provider.Settings
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.settingslib.spa.testutils.firstWithTimeoutOrNull
+import com.android.settingslib.spa.testutils.toListWithTimeout
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.async
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.runBlocking
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class SettingsSecureStringTest {
+
+ private val context: Context = ApplicationProvider.getApplicationContext()
+
+ @Test
+ fun getValue_returnCorrectValue() {
+ Settings.Secure.putString(context.contentResolver, TEST_NAME, VALUE)
+
+ val value by context.settingsSecureString(TEST_NAME)
+
+ assertThat(value).isEqualTo(VALUE)
+ }
+
+ @Test
+ fun setValue_correctValueSet() {
+ var value by context.settingsSecureString(TEST_NAME)
+
+ value = VALUE
+
+ assertThat(Settings.Secure.getString(context.contentResolver, TEST_NAME)).isEqualTo(VALUE)
+ }
+
+ @Test
+ fun settingsSecureStringFlow_valueNotChanged() = runBlocking {
+ var value by context.settingsSecureString(TEST_NAME)
+ value = VALUE
+
+ val flow = context.settingsSecureStringFlow(TEST_NAME)
+
+ assertThat(flow.firstWithTimeoutOrNull()).isEqualTo(VALUE)
+ }
+
+ @Test
+ fun settingsSecureStringFlow_collectAfterValueChanged_onlyKeepLatest() = runBlocking {
+ var value by context.settingsSecureString(TEST_NAME)
+ value = ""
+
+ val flow = context.settingsSecureStringFlow(TEST_NAME)
+ value = VALUE
+
+ assertThat(flow.firstWithTimeoutOrNull()).isEqualTo(VALUE)
+ }
+
+ @Test
+ fun settingsSecureStringFlow_collectBeforeValueChanged_getBoth() = runBlocking {
+ var value by context.settingsSecureString(TEST_NAME)
+ value = ""
+
+ val listDeferred = async { context.settingsSecureStringFlow(TEST_NAME).toListWithTimeout() }
+ delay(100)
+ value = VALUE
+
+ assertThat(listDeferred.await()).containsAtLeast("", VALUE).inOrder()
+ }
+
+ private companion object {
+ const val TEST_NAME = "test_string_delegate"
+ const val VALUE = "value"
+ }
+}
diff --git a/packages/SettingsLib/aconfig/settingslib.aconfig b/packages/SettingsLib/aconfig/settingslib.aconfig
index 32557b9..a158756 100644
--- a/packages/SettingsLib/aconfig/settingslib.aconfig
+++ b/packages/SettingsLib/aconfig/settingslib.aconfig
@@ -79,3 +79,13 @@
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ name: "enable_determining_spatial_audio_attributes_by_profile"
+ namespace: "cross_device_experiences"
+ description: "Use bluetooth profile connection policy to determine spatial audio attributes"
+ bug: "341005211"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/volume/data/repository/AudioRepository.kt b/packages/SettingsLib/src/com/android/settingslib/volume/data/repository/AudioRepository.kt
index 20b949f4..8ec5ba1 100644
--- a/packages/SettingsLib/src/com/android/settingslib/volume/data/repository/AudioRepository.kt
+++ b/packages/SettingsLib/src/com/android/settingslib/volume/data/repository/AudioRepository.kt
@@ -20,6 +20,7 @@
import android.database.ContentObserver
import android.media.AudioDeviceInfo
import android.media.AudioManager
+import android.media.AudioManager.AudioDeviceCategory
import android.media.AudioManager.OnCommunicationDeviceChangedListener
import android.provider.Settings
import androidx.concurrent.futures.DirectExecutor
@@ -85,6 +86,10 @@
suspend fun setMuted(audioStream: AudioStream, isMuted: Boolean): Boolean
suspend fun setRingerMode(audioStream: AudioStream, mode: RingerMode)
+
+ /** Gets audio device category. */
+ @AudioDeviceCategory
+ suspend fun getBluetoothAudioDeviceCategory(bluetoothAddress: String): Int
}
class AudioRepositoryImpl(
@@ -211,6 +216,13 @@
withContext(backgroundCoroutineContext) { audioManager.ringerMode = mode.value }
}
+ @AudioDeviceCategory
+ override suspend fun getBluetoothAudioDeviceCategory(bluetoothAddress: String): Int {
+ return withContext(backgroundCoroutineContext) {
+ audioManager.getBluetoothAudioDeviceCategory(bluetoothAddress)
+ }
+ }
+
private fun getMinVolume(stream: AudioStream): Int =
try {
audioManager.getStreamMinVolume(stream.value)
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/volume/data/repository/AudioRepositoryTest.kt b/packages/SettingsLib/tests/integ/src/com/android/settingslib/volume/data/repository/AudioRepositoryTest.kt
index 683759d..844dc12 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/volume/data/repository/AudioRepositoryTest.kt
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/volume/data/repository/AudioRepositoryTest.kt
@@ -247,6 +247,19 @@
}
}
+ @Test
+ fun getBluetoothAudioDeviceCategory() {
+ testScope.runTest {
+ `when`(audioManager.getBluetoothAudioDeviceCategory("12:34:56:78")).thenReturn(
+ AudioManager.AUDIO_DEVICE_CATEGORY_HEADPHONES)
+
+ val category = underTest.getBluetoothAudioDeviceCategory("12:34:56:78")
+ runCurrent()
+
+ assertThat(category).isEqualTo(AudioManager.AUDIO_DEVICE_CATEGORY_HEADPHONES)
+ }
+ }
+
private fun triggerConnectedDeviceChange(communicationDevice: AudioDeviceInfo?) {
verify(audioManager)
.addOnCommunicationDeviceChangedListener(
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
index 9f2ab69..8d02dbd 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
@@ -279,5 +279,6 @@
Settings.Secure.ON_DEVICE_INTELLIGENCE_UNBIND_TIMEOUT_MS,
Settings.Secure.ON_DEVICE_INFERENCE_UNBIND_TIMEOUT_MS,
Settings.Secure.ON_DEVICE_INTELLIGENCE_IDLE_TIMEOUT_MS,
+ Settings.Secure.MANDATORY_BIOMETRICS,
};
}
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
index cb7ac45..7169cf7 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -438,5 +438,6 @@
VALIDATORS.put(Secure.ON_DEVICE_INFERENCE_UNBIND_TIMEOUT_MS, ANY_LONG_VALIDATOR);
VALIDATORS.put(Secure.ON_DEVICE_INTELLIGENCE_UNBIND_TIMEOUT_MS, ANY_LONG_VALIDATOR);
VALIDATORS.put(Secure.ON_DEVICE_INTELLIGENCE_IDLE_TIMEOUT_MS, NONE_NEGATIVE_LONG_VALIDATOR);
+ VALIDATORS.put(Secure.MANDATORY_BIOMETRICS, new InclusiveIntegerRangeValidator(0, 1));
}
}
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index fde7c2c..bd7c9a0 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -98,13 +98,66 @@
],
}
-// Tests where robolectric failed at runtime. (go/multivalent-tests)
+// Tests where robolectric failed at runtime. (go/central-multivalent)
filegroup {
name: "SystemUI-tests-broken-robofiles-run",
srcs: [
+ "tests/src/**/systemui/ExpandHelperTest.java",
+ "tests/src/**/AAAPlusPlusVerifySysuiRequiredTestPropertiesTest.java",
+ "tests/src/**/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuControllerTest.java",
+ "tests/src/**/systemui/accessibility/floatingmenu/AccessibilityTargetAdapterTest.java",
+ "tests/src/**/systemui/screenshot/appclips/AppClipsActivityTest.java",
+ "tests/src/**/systemui/screenshot/appclips/AppClipsTrampolineActivityTest.java",
+ "tests/src/**/systemui/screenshot/appclips/AppClipsViewModelTest.java",
+ "tests/src/**/systemui/appops/AppOpsControllerTest.java",
+ "tests/src/**/systemui/biometrics/BiometricNotificationServiceTest.java",
+ "tests/src/**/systemui/bluetooth/BroadcastDialogDelegateTest.java",
+ "tests/src/**/systemui/clipboardoverlay/ClipboardOverlayControllerTest.java",
+ "tests/src/**/systemui/communal/data/backup/CommunalBackupHelperTest.kt",
+ "tests/src/**/systemui/controls/ui/ControlsPopupMenuTest.kt",
+ "tests/src/**/systemui/classifier/DistanceClassifierTest.java",
+ "tests/src/**/systemui/doze/DozeScreenBrightnessTest.java",
+ "tests/src/**/systemui/doze/DozeSensorsTest.java",
+ "tests/src/**/systemui/doze/DozeTriggersTest.java",
+ "tests/src/**/systemui/classifier/FalsingDataProviderTest.java",
+ "tests/src/**/systemui/screenshot/ImageExporterTest.java",
+ "tests/src/**/systemui/bouncer/data/repository/KeyguardBouncerRepositoryTest.kt",
+ "tests/src/**/systemui/keyguard/domain/interactor/scenetransition/LockscreenSceneTransitionInteractorTest.kt",
+ "tests/src/**/systemui/logcat/LogAccessDialogActivityTest.java",
+ "tests/src/**/systemui/media/controls/domain/pipeline/MediaDeviceManagerTest.kt",
+ "tests/src/**/systemui/media/controls/domain/pipeline/MediaSessionBasedFilterTest.kt",
+ "tests/src/**/systemui/accessibility/floatingmenu/MenuNotificationFactoryTest.java",
+ "tests/src/**/systemui/accessibility/floatingmenu/MenuViewLayerTest.java",
+ "tests/src/**/systemui/accessibility/floatingmenu/MenuViewTest.java",
+ "tests/src/**/systemui/classifier/PointerCountClassifierTest.java",
+ "tests/src/**/systemui/qs/tileimpl/QSIconViewImplTest_311121830.kt",
+ "tests/src/**/systemui/accessibility/floatingmenu/RadiiAnimatorTest.java",
+ "tests/src/**/systemui/screenrecord/RecordingControllerTest.java",
+ "tests/src/**/systemui/screenshot/RequestProcessorTest.kt",
+ "tests/src/**/systemui/media/controls/domain/resume/ResumeMediaBrowserTest.kt",
+ "tests/src/**/systemui/screenshot/SaveImageInBackgroundTaskTest.kt",
+ "tests/src/**/systemui/screenshot/scroll/ScrollCaptureClientTest.java",
+ "tests/src/**/systemui/accessibility/SecureSettingsContentObserverTest.java",
+ "tests/src/**/systemui/media/controls/ui/viewmodel/SeekBarViewModelTest.kt",
+ "tests/src/**/systemui/qs/external/TileServicesTest.java",
+ "tests/src/**/systemui/ambient/touch/TouchMonitorTest.java",
+ "tests/src/**/systemui/accessibility/WindowMagnificationControllerWindowlessMagnifierTest.java",
+ "tests/src/**/systemui/accessibility/WindowMagnificationSettingsTest.java",
+ "tests/src/androidx/core/animation/AnimatorTestRuleIsolationTest.kt",
+ "tests/src/**/systemui/CameraProtectionLoaderImplTest.kt",
+ "tests/src/**/systemui/DependencyTest.java",
+ "tests/src/**/systemui/InitControllerTest.java",
+ "tests/src/**/systemui/SliceBroadcastRelayHandlerTest.java",
+ "tests/src/**/systemui/SystemUIApplicationTest.kt",
+ "tests/src/**/systemui/SysUICutoutProviderTest.kt",
+ "tests/src/**/keyguard/ActiveUnlockConfigTest.kt",
+ "tests/src/**/keyguard/AdminSecondaryLockScreenControllerTest.java",
+ "tests/src/**/keyguard/KeyguardClockAccessibilityDelegateTest.java",
+ "tests/src/**/keyguard/KeyguardStatusViewControllerTest.java",
"tests/src/**/systemui/accessibility/AccessibilityButtonModeObserverTest.java",
"tests/src/**/systemui/accessibility/AccessibilityButtonTargetsObserverTest.java",
"tests/src/**/systemui/accessibility/FullscreenMagnificationControllerTest.java",
+ "tests/src/**/systemui/accessibility/MagnificationTest.java",
"tests/src/**/systemui/accessibility/WindowMagnificationAnimationControllerTest.java",
"tests/src/**/systemui/animation/FontInterpolatorTest.kt",
"tests/src/**/systemui/animation/TextAnimatorTest.kt",
@@ -160,6 +213,7 @@
"tests/src/**/systemui/statusbar/KeyboardShortcutsTest.java",
"tests/src/**/systemui/statusbar/KeyguardIndicationControllerWithCoroutinesTest.kt",
"tests/src/**/systemui/statusbar/notification/AssistantFeedbackControllerTest.java",
+ "tests/src/**/systemui/statusbar/notification/PropertyAnimatorTest.java",
"tests/src/**/systemui/statusbar/notification/collection/NotifCollectionTest.java",
"tests/src/**/systemui/statusbar/notification/collection/NotificationEntryTest.java",
"tests/src/**/systemui/statusbar/notification/collection/render/GroupExpansionManagerTest.kt",
diff --git a/packages/SystemUI/aconfig/accessibility.aconfig b/packages/SystemUI/aconfig/accessibility.aconfig
index d201071..f63a896 100644
--- a/packages/SystemUI/aconfig/accessibility.aconfig
+++ b/packages/SystemUI/aconfig/accessibility.aconfig
@@ -73,6 +73,16 @@
}
flag {
+ name: "redesign_magnifier_window_size"
+ namespace: "accessibility"
+ description: "Redesigns the window magnification magnifier sizes provided in the settings panel."
+ bug: "288056772"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
name: "save_and_restore_magnification_settings_buttons"
namespace: "accessibility"
description: "Saves the selected button status in magnification settings and restore the status when revisiting the same smallest screen DP."
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index ffa1db3..0ccaf18 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -867,6 +867,13 @@
}
flag {
+ name: "keyboard_touchpad_contextual_education"
+ namespace: "systemui"
+ description: "Allow showing education for physical keyboard and touchpad"
+ bug: "317496783"
+}
+
+flag {
name: "dream_overlay_bouncer_swipe_direction_filtering"
namespace: "systemui"
description: "do not initiate bouncer swipe when the direction is opposite of the expansion"
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContent.kt
index 18085ab..7d82920 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContent.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContent.kt
@@ -29,6 +29,7 @@
import com.android.systemui.communal.ui.compose.section.AmbientStatusBarSection
import com.android.systemui.communal.ui.viewmodel.CommunalViewModel
import com.android.systemui.keyguard.ui.composable.blueprint.BlueprintAlignmentLines
+import com.android.systemui.keyguard.ui.composable.section.BottomAreaSection
import com.android.systemui.keyguard.ui.composable.section.LockSection
import com.android.systemui.statusbar.phone.SystemUIDialogFactory
import javax.inject.Inject
@@ -41,8 +42,10 @@
private val interactionHandler: SmartspaceInteractionHandler,
private val dialogFactory: SystemUIDialogFactory,
private val lockSection: LockSection,
+ private val bottomAreaSection: BottomAreaSection,
private val ambientStatusBarSection: AmbientStatusBarSection,
) {
+
@Composable
fun SceneScope.Content(modifier: Modifier = Modifier) {
Layout(
@@ -65,10 +68,16 @@
modifier = Modifier.element(Communal.Elements.LockIcon)
)
}
+ with(bottomAreaSection) {
+ IndicationArea(
+ Modifier.element(Communal.Elements.IndicationArea).fillMaxWidth()
+ )
+ }
}
) { measurables, constraints ->
val communalGridMeasurable = measurables[0]
val lockIconMeasurable = measurables[1]
+ val bottomAreaMeasurable = measurables[2]
val noMinConstraints =
constraints.copy(
@@ -85,6 +94,13 @@
bottom = lockIconPlaceable[BlueprintAlignmentLines.LockIcon.Bottom],
)
+ val bottomAreaPlaceable =
+ bottomAreaMeasurable.measure(
+ noMinConstraints.copy(
+ maxHeight = (constraints.maxHeight - lockIconBounds.bottom).coerceAtLeast(0)
+ )
+ )
+
val communalGridPlaceable =
communalGridMeasurable.measure(
noMinConstraints.copy(maxHeight = lockIconBounds.top)
@@ -99,6 +115,10 @@
x = lockIconBounds.left,
y = lockIconBounds.top,
)
+ bottomAreaPlaceable.place(
+ x = 0,
+ y = constraints.maxHeight - bottomAreaPlaceable.height,
+ )
}
}
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
index 4dc801c..7062489 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
@@ -52,10 +52,12 @@
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.requiredSize
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.layout.widthIn
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.GridItemSpan
@@ -75,12 +77,15 @@
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults
+import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.FilledIconButton
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButtonColors
import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.ModalBottomSheet
import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.Text
+import androidx.compose.material3.rememberModalBottomSheetState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.State
@@ -153,7 +158,7 @@
import com.android.systemui.statusbar.phone.SystemUIDialogFactory
import kotlinx.coroutines.launch
-@OptIn(ExperimentalComposeUiApi::class)
+@OptIn(ExperimentalComposeUiApi::class, ExperimentalMaterial3Api::class)
@Composable
fun CommunalHub(
modifier: Modifier = Modifier,
@@ -378,6 +383,33 @@
onCancel = viewModel::onEnableWorkProfileDialogCancel
)
}
+
+ if (viewModel is CommunalEditModeViewModel) {
+ val showBottomSheet by viewModel.showDisclaimer.collectAsStateWithLifecycle(false)
+
+ if (showBottomSheet) {
+ val scope = rememberCoroutineScope()
+ val sheetState = rememberModalBottomSheetState()
+ val colors = LocalAndroidColorScheme.current
+
+ ModalBottomSheet(
+ onDismissRequest = viewModel::onDisclaimerDismissed,
+ sheetState = sheetState,
+ dragHandle = null,
+ containerColor = colors.surfaceContainer,
+ ) {
+ DisclaimerBottomSheetContent {
+ scope
+ .launch { sheetState.hide() }
+ .invokeOnCompletion {
+ if (!sheetState.isVisible) {
+ viewModel.onDisclaimerDismissed()
+ }
+ }
+ }
+ }
+ }
+ }
}
}
@@ -389,6 +421,47 @@
viewModel.signalUserInteraction()
}
+@Composable
+private fun DisclaimerBottomSheetContent(onButtonClicked: () -> Unit) {
+ val colors = LocalAndroidColorScheme.current
+
+ Column(
+ modifier = Modifier.fillMaxWidth().padding(horizontal = 32.dp, vertical = 24.dp),
+ verticalArrangement = Arrangement.Center,
+ horizontalAlignment = Alignment.CenterHorizontally,
+ ) {
+ Icon(
+ imageVector = Icons.Outlined.Widgets,
+ contentDescription = null,
+ tint = colors.primary,
+ modifier = Modifier.size(32.dp)
+ )
+ Spacer(modifier = Modifier.height(16.dp))
+ Text(
+ text = stringResource(R.string.communal_widgets_disclaimer_title),
+ style = MaterialTheme.typography.headlineMedium,
+ color = colors.onSurface,
+ )
+ Spacer(modifier = Modifier.height(16.dp))
+ Text(
+ text = stringResource(R.string.communal_widgets_disclaimer_text),
+ color = colors.onSurfaceVariant,
+ )
+ Button(
+ modifier =
+ Modifier.padding(horizontal = 26.dp, vertical = 16.dp)
+ .widthIn(min = 200.dp)
+ .heightIn(min = 56.dp),
+ onClick = { onButtonClicked() }
+ ) {
+ Text(
+ stringResource(R.string.communal_widgets_disclaimer_button),
+ style = MaterialTheme.typography.labelLarge,
+ )
+ }
+ }
+}
+
/**
* Observes communal content and scrolls to any added or updated live content, e.g. a new media
* session is started, or a paused timer is resumed.
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/BottomAreaSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/BottomAreaSection.kt
index 97d5b41..86639fa 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/BottomAreaSection.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/BottomAreaSection.kt
@@ -24,6 +24,7 @@
import androidx.compose.foundation.layout.size
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.unit.DpSize
@@ -183,7 +184,7 @@
indicationController: KeyguardIndicationController,
modifier: Modifier = Modifier,
) {
- val (disposable, setDisposable) = mutableStateOf<DisposableHandle?>(null)
+ val (disposable, setDisposable) = remember { mutableStateOf<DisposableHandle?>(null) }
AndroidView(
factory = { context ->
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt
index 29223ce..6805888 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt
@@ -94,6 +94,7 @@
val HeadsUpNotificationPlaceholder =
ElementKey("HeadsUpNotificationPlaceholder", scenePicker = LowestZIndexScenePicker)
val ShelfSpace = ElementKey("ShelfSpace")
+ val NotificationStackCutoffGuideline = ElementKey("NotificationStackCutoffGuideline")
}
// Expansion fraction thresholds (between 0-1f) at which the corresponding value should be
@@ -410,18 +411,22 @@
* the notification contents (stack, footer, shelf) should be drawn.
*/
@Composable
-fun NotificationStackCutoffGuideline(
+fun SceneScope.NotificationStackCutoffGuideline(
stackScrollView: NotificationScrollView,
viewModel: NotificationsPlaceholderViewModel,
modifier: Modifier = Modifier,
) {
Spacer(
modifier =
- modifier.fillMaxWidth().height(0.dp).onGloballyPositioned { coordinates ->
- val positionY = coordinates.positionInWindow().y
- debugLog(viewModel) { "STACK cutoff onGloballyPositioned: y=$positionY" }
- stackScrollView.setStackCutoff(positionY)
- }
+ modifier
+ .element(key = Notifications.Elements.NotificationStackCutoffGuideline)
+ .fillMaxWidth()
+ .height(0.dp)
+ .onGloballyPositioned { coordinates ->
+ val positionY = coordinates.positionInWindow().y
+ debugLog(viewModel) { "STACK cutoff onGloballyPositioned: y=$positionY" }
+ stackScrollView.setStackCutoff(positionY)
+ }
)
}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateToScene.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateToScene.kt
index c2dd803..ea740a8 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateToScene.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateToScene.kt
@@ -48,8 +48,15 @@
}
return when (transitionState) {
- is TransitionState.Idle ->
- animate(layoutState, target, transitionKey, isInitiatedByUserInput = false)
+ is TransitionState.Idle -> {
+ animate(
+ layoutState,
+ target,
+ transitionKey,
+ isInitiatedByUserInput = false,
+ replacedTransition = null,
+ )
+ }
is TransitionState.Transition -> {
val isInitiatedByUserInput = transitionState.isInitiatedByUserInput
@@ -79,6 +86,7 @@
isInitiatedByUserInput,
initialProgress = progress,
initialVelocity = transitionState.progressVelocity,
+ replacedTransition = transitionState,
)
}
} else if (transitionState.fromScene == target) {
@@ -101,6 +109,7 @@
initialProgress = progress,
initialVelocity = transitionState.progressVelocity,
reversed = true,
+ replacedTransition = transitionState,
)
}
} else {
@@ -137,6 +146,7 @@
isInitiatedByUserInput,
fromScene = animateFrom,
chain = chain,
+ replacedTransition = null,
)
}
}
@@ -148,6 +158,7 @@
targetScene: SceneKey,
transitionKey: TransitionKey?,
isInitiatedByUserInput: Boolean,
+ replacedTransition: TransitionState.Transition?,
initialProgress: Float = 0f,
initialVelocity: Float = 0f,
reversed: Boolean = false,
@@ -164,6 +175,7 @@
currentScene = targetScene,
isInitiatedByUserInput = isInitiatedByUserInput,
isUserInputOngoing = false,
+ replacedTransition = replacedTransition,
)
} else {
OneOffTransition(
@@ -173,6 +185,7 @@
currentScene = targetScene,
isInitiatedByUserInput = isInitiatedByUserInput,
isUserInputOngoing = false,
+ replacedTransition = replacedTransition,
)
}
@@ -214,7 +227,8 @@
override val currentScene: SceneKey,
override val isInitiatedByUserInput: Boolean,
override val isUserInputOngoing: Boolean,
-) : TransitionState.Transition(fromScene, toScene) {
+ replacedTransition: TransitionState.Transition?,
+) : TransitionState.Transition(fromScene, toScene, replacedTransition) {
/**
* The animatable used to animate this transition.
*
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt
index 837c292a..e313aa5 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt
@@ -37,7 +37,7 @@
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
-interface DraggableHandler {
+internal interface DraggableHandler {
/**
* Start a drag in the given [startedPosition], with the given [overSlop] and number of
* [pointersDown].
@@ -51,7 +51,7 @@
* The [DragController] provides control over the transition between two scenes through the [onDrag]
* and [onStop] methods.
*/
-interface DragController {
+internal interface DragController {
/** Drag the current scene by [delta] pixels. */
fun onDrag(delta: Float)
@@ -395,10 +395,11 @@
if (
distance != DistanceUnspecified &&
shouldCommitSwipe(
- offset,
- distance,
- velocity,
+ offset = offset,
+ distance = distance,
+ velocity = velocity,
wasCommitted = swipeTransition._currentScene == toScene,
+ requiresFullDistanceSwipe = swipeTransition.requiresFullDistanceSwipe,
)
) {
targetScene = toScene
@@ -472,7 +473,12 @@
distance: Float,
velocity: Float,
wasCommitted: Boolean,
+ requiresFullDistanceSwipe: Boolean,
): Boolean {
+ if (requiresFullDistanceSwipe && !wasCommitted) {
+ return offset / distance >= 1f
+ }
+
fun isCloserToTarget(): Boolean {
return (offset - distance).absoluteValue < offset.absoluteValue
}
@@ -530,6 +536,8 @@
userActionDistanceScope = layoutImpl.userActionDistanceScope,
orientation = orientation,
isUpOrLeft = isUpOrLeft,
+ requiresFullDistanceSwipe = result.requiresFullDistanceSwipe,
+ replacedTransition = null,
)
}
@@ -545,6 +553,8 @@
orientation = old.orientation,
isUpOrLeft = old.isUpOrLeft,
lastDistance = old.lastDistance,
+ requiresFullDistanceSwipe = old.requiresFullDistanceSwipe,
+ replacedTransition = old,
)
.apply {
_currentScene = old._currentScene
@@ -562,9 +572,11 @@
val userActionDistanceScope: UserActionDistanceScope,
override val orientation: Orientation,
override val isUpOrLeft: Boolean,
+ val requiresFullDistanceSwipe: Boolean,
+ replacedTransition: SwipeTransition?,
var lastDistance: Float = DistanceUnspecified,
) :
- TransitionState.Transition(_fromScene.key, _toScene.key),
+ TransitionState.Transition(_fromScene.key, _toScene.key, replacedTransition),
TransitionState.HasOverscrollProperties {
var _currentScene by mutableStateOf(_fromScene)
override val currentScene: SceneKey
@@ -901,6 +913,7 @@
private val topOrLeftBehavior: NestedScrollBehavior,
private val bottomOrRightBehavior: NestedScrollBehavior,
private val isExternalOverscrollGesture: () -> Boolean,
+ private val pointersInfo: () -> PointersInfo,
) {
private val layoutState = layoutImpl.state
private val draggableHandler = layoutImpl.draggableHandler(orientation)
@@ -912,34 +925,36 @@
// moving on to the next scene.
var canChangeScene = false
- val actionUpOrLeft =
- Swipe(
- direction =
- when (orientation) {
- Orientation.Horizontal -> SwipeDirection.Left
- Orientation.Vertical -> SwipeDirection.Up
- },
- pointerCount = 1,
- )
-
- val actionDownOrRight =
- Swipe(
- direction =
- when (orientation) {
- Orientation.Horizontal -> SwipeDirection.Right
- Orientation.Vertical -> SwipeDirection.Down
- },
- pointerCount = 1,
- )
-
fun hasNextScene(amount: Float): Boolean {
val transitionState = layoutState.transitionState
val scene = transitionState.currentScene
val fromScene = layoutImpl.scene(scene)
val nextScene =
when {
- amount < 0f -> fromScene.userActions[actionUpOrLeft]
- amount > 0f -> fromScene.userActions[actionDownOrRight]
+ amount < 0f -> {
+ val actionUpOrLeft =
+ Swipe(
+ direction =
+ when (orientation) {
+ Orientation.Horizontal -> SwipeDirection.Left
+ Orientation.Vertical -> SwipeDirection.Up
+ },
+ pointerCount = pointersInfo().pointersDown,
+ )
+ fromScene.userActions[actionUpOrLeft]
+ }
+ amount > 0f -> {
+ val actionDownOrRight =
+ Swipe(
+ direction =
+ when (orientation) {
+ Orientation.Horizontal -> SwipeDirection.Right
+ Orientation.Vertical -> SwipeDirection.Down
+ },
+ pointerCount = pointersInfo().pointersDown,
+ )
+ fromScene.userActions[actionDownOrRight]
+ }
else -> null
}
if (nextScene != null) return true
@@ -1037,10 +1052,11 @@
canContinueScroll = { true },
canScrollOnFling = false,
onStart = { offsetAvailable ->
+ val pointers = pointersInfo()
dragController =
draggableHandler.onDragStarted(
- pointersDown = 1,
- startedPosition = null,
+ pointersDown = pointers.pointersDown,
+ startedPosition = pointers.startedPosition,
overSlop = if (isIntercepting) 0f else offsetAvailable,
)
},
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt
index 09d11b7..69124c1 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt
@@ -306,7 +306,6 @@
return layout(placeable.width, placeable.height) { place(transition, placeable) }
}
- @OptIn(ExperimentalComposeUiApi::class)
private fun Placeable.PlacementScope.place(
transition: TransitionState.Transition?,
placeable: Placeable,
@@ -496,6 +495,10 @@
transition: TransitionState.Transition,
previousTransition: TransitionState.Transition,
) {
+ if (transition.replacedTransition == previousTransition) {
+ return
+ }
+
val sceneStates = element.sceneStates
fun updatedSceneState(key: SceneKey): Element.SceneState? {
return sceneStates[key]?.also { it.selfUpdateValuesBeforeInterruption() }
@@ -561,10 +564,20 @@
}
private fun Element.SceneState.selfUpdateValuesBeforeInterruption() {
- offsetBeforeInterruption = lastOffset
sizeBeforeInterruption = lastSize
- scaleBeforeInterruption = lastScale
- alphaBeforeInterruption = lastAlpha
+
+ if (lastAlpha > 0f) {
+ offsetBeforeInterruption = lastOffset
+ scaleBeforeInterruption = lastScale
+ alphaBeforeInterruption = lastAlpha
+ } else {
+ // Consider the element as not placed in this scene if it was fully transparent.
+ // TODO(b/290930950): Look into using derived state inside place() instead to not even place
+ // the element at all when alpha == 0f.
+ offsetBeforeInterruption = Offset.Unspecified
+ scaleBeforeInterruption = Scale.Unspecified
+ alphaBeforeInterruption = Element.AlphaUnspecified
+ }
}
private fun Element.SceneState.updateValuesBeforeInterruption(lastState: Element.SceneState) {
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MultiPointerDraggable.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MultiPointerDraggable.kt
index 6001f1f..572b1d7 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MultiPointerDraggable.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MultiPointerDraggable.kt
@@ -138,11 +138,26 @@
}
}
+ private var _toFloat = orientation.toFunctionOffsetToFloat()
+
+ private fun Offset.toFloat(): Float = _toFloat(this)
+
+ private fun Orientation.toFunctionOffsetToFloat(): (Offset) -> Float =
+ when (this) {
+ Orientation.Vertical -> {
+ { it.y }
+ }
+ Orientation.Horizontal -> {
+ { it.x }
+ }
+ }
+
var orientation: Orientation = orientation
set(value) {
// Reset the pointer input whenever orientation changed.
if (value != field) {
field = value
+ _toFloat = field.toFunctionOffsetToFloat()
delegate.resetPointerInputHandler()
}
}
@@ -367,13 +382,6 @@
return event
}
- private fun Offset.toFloat(): Float {
- return when (orientation) {
- Orientation.Vertical -> y
- Orientation.Horizontal -> x
- }
- }
-
/**
* Continues to read drag events until all pointers are up or the drag event is canceled. The
* initial pointer to use for driving the drag is [initialPointerId]. [hasDragged] passes the
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/NestedScrollToScene.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/NestedScrollToScene.kt
index 1fa6b3f7..dd795cd 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/NestedScrollToScene.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/NestedScrollToScene.kt
@@ -18,12 +18,21 @@
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.ui.Modifier
+import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.input.nestedscroll.nestedScrollModifierNode
+import androidx.compose.ui.input.pointer.PointerEventPass
+import androidx.compose.ui.input.pointer.PointerInputChange
+import androidx.compose.ui.input.pointer.PointerInputScope
+import androidx.compose.ui.input.pointer.SuspendingPointerInputModifierNode
import androidx.compose.ui.node.DelegatableNode
import androidx.compose.ui.node.DelegatingNode
import androidx.compose.ui.node.ModifierNodeElement
import androidx.compose.ui.platform.InspectorInfo
+import androidx.compose.ui.util.fastMap
+import androidx.compose.ui.util.fastReduce
import com.android.compose.nestedscroll.PriorityNestedScrollConnection
+import kotlinx.coroutines.coroutineScope
+import kotlinx.coroutines.isActive
/**
* Defines the behavior of the [SceneTransitionLayout] when a scrollable component is scrolled.
@@ -121,6 +130,11 @@
}
}
+internal data class PointersInfo(
+ val pointersDown: Int,
+ val startedPosition: Offset,
+)
+
private class NestedScrollToSceneNode(
layoutImpl: SceneTransitionLayoutImpl,
orientation: Orientation,
@@ -135,23 +149,49 @@
topOrLeftBehavior = topOrLeftBehavior,
bottomOrRightBehavior = bottomOrRightBehavior,
isExternalOverscrollGesture = isExternalOverscrollGesture,
+ pointersInfo = pointerInfo()
)
+ private var lastPointers: List<PointerInputChange>? = null
+
+ private fun pointerInfo(): () -> PointersInfo = {
+ val pointers =
+ requireNotNull(lastPointers) { "NestedScroll API was called before PointerInput API" }
+ PointersInfo(
+ pointersDown = pointers.size,
+ startedPosition = pointers.fastMap { it.position }.fastReduce { a, b -> (a + b) / 2f },
+ )
+ }
+
+ private val pointerInputHandler: suspend PointerInputScope.() -> Unit = {
+ coroutineScope {
+ awaitPointerEventScope {
+ // Await this scope to guarantee that the PointerInput API receives touch events
+ // before the NestedScroll API.
+ delegate(nestedScrollNode)
+
+ try {
+ while (isActive) {
+ // During the initial phase, we receive the event after our ancestors.
+ lastPointers = awaitPointerEvent(PointerEventPass.Initial).changes
+ }
+ } finally {
+ // Clean up the nested scroll connection
+ priorityNestedScrollConnection.reset()
+ undelegate(nestedScrollNode)
+ }
+ }
+ }
+ }
+
+ private val pointerInputNode = delegate(SuspendingPointerInputModifierNode(pointerInputHandler))
+
private var nestedScrollNode: DelegatableNode =
nestedScrollModifierNode(
connection = priorityNestedScrollConnection,
dispatcher = null,
)
- override fun onAttach() {
- delegate(nestedScrollNode)
- }
-
- override fun onDetach() {
- // Make sure we reset the scroll connection when this modifier is removed from composition
- priorityNestedScrollConnection.reset()
- }
-
fun update(
layoutImpl: SceneTransitionLayoutImpl,
orientation: Orientation,
@@ -161,7 +201,7 @@
) {
// Clean up the old nested scroll connection
priorityNestedScrollConnection.reset()
- undelegate(nestedScrollNode)
+ pointerInputNode.resetPointerInputHandler()
// Create a new nested scroll connection
priorityNestedScrollConnection =
@@ -171,13 +211,13 @@
topOrLeftBehavior = topOrLeftBehavior,
bottomOrRightBehavior = bottomOrRightBehavior,
isExternalOverscrollGesture = isExternalOverscrollGesture,
+ pointersInfo = pointerInfo(),
)
nestedScrollNode =
nestedScrollModifierNode(
connection = priorityNestedScrollConnection,
dispatcher = null,
)
- delegate(nestedScrollNode)
}
}
@@ -187,6 +227,7 @@
topOrLeftBehavior: NestedScrollBehavior,
bottomOrRightBehavior: NestedScrollBehavior,
isExternalOverscrollGesture: () -> Boolean,
+ pointersInfo: () -> PointersInfo,
) =
NestedScrollHandlerImpl(
layoutImpl = layoutImpl,
@@ -194,5 +235,6 @@
topOrLeftBehavior = topOrLeftBehavior,
bottomOrRightBehavior = bottomOrRightBehavior,
isExternalOverscrollGesture = isExternalOverscrollGesture,
+ pointersInfo = pointersInfo,
)
.connection
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt
index 33063c8..7c8fce8 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt
@@ -459,6 +459,13 @@
/** The key of the transition that should be used. */
val transitionKey: TransitionKey? = null,
+
+ /**
+ * If `true`, the swipe will be committed and we will settle to [toScene] if only if the user
+ * swiped at least the swipe distance, i.e. the transition progress was already equal to or
+ * bigger than 100% when the user released their finger. `
+ */
+ val requiresFullDistanceSwipe: Boolean = false,
)
fun interface UserActionDistance {
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
index a8df6f4..5b4fbf0 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
@@ -224,6 +224,9 @@
/** The scene this transition is going to. Can't be the same as fromScene */
val toScene: SceneKey,
+
+ /** The transition that `this` transition is replacing, if any. */
+ internal val replacedTransition: Transition? = null,
) : TransitionState {
/**
* The key of this transition. This should usually be null, but it can be specified to use a
@@ -279,6 +282,11 @@
init {
check(fromScene != toScene)
+ check(
+ replacedTransition == null ||
+ (replacedTransition.fromScene == fromScene &&
+ replacedTransition.toScene == toScene)
+ )
}
/**
@@ -321,6 +329,10 @@
return 0f
}
+ if (replacedTransition != null) {
+ return replacedTransition.interruptionProgress(layoutImpl)
+ }
+
fun create(): Animatable<Float, AnimationVector1D> {
val animatable = Animatable(1f, visibilityThreshold = ProgressVisibilityThreshold)
layoutImpl.coroutineScope.launch {
@@ -521,6 +533,10 @@
check(transitionStates.size == 1)
check(transitionStates[0] is TransitionState.Idle)
transitionStates = listOf(transition)
+ } else if (currentState == transition.replacedTransition) {
+ // Replace the transition.
+ transitionStates =
+ transitionStates.subList(0, transitionStates.lastIndex) + transition
} else {
// Append the new transition.
transitionStates = transitionStates + transition
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/modifiers/SizeMatcher.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/modifiers/SizeMatcher.kt
new file mode 100644
index 0000000..a4bd2be
--- /dev/null
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/modifiers/SizeMatcher.kt
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.compose.animation.scene.modifiers
+
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.layout.Measurable
+import androidx.compose.ui.layout.MeasureResult
+import androidx.compose.ui.layout.MeasureScope
+import androidx.compose.ui.node.LayoutModifierNode
+import androidx.compose.ui.node.ModifierNodeElement
+import androidx.compose.ui.node.invalidateMeasurement
+import androidx.compose.ui.unit.Constraints
+import androidx.compose.ui.unit.IntSize
+import androidx.compose.ui.unit.constrain
+
+/**
+ * An object to make one or more destination node be the same size as a source node.
+ *
+ * Important: Most of the time, you should not use this class and instead use `Box` together with
+ * `Modifier.matchParentSize()`. Use this only if you need to use both `Modifier.element()` and
+ * `Modifier.matchParentSize()` (see b/347910697 for details).
+ *
+ * Example:
+ * ```
+ * Box {
+ * val sizeMatcher = remember { SizeMatcher() }
+ *
+ * // The content.
+ * Content(Modifier.sizeMatcherSource(sizeMatcher))
+ *
+ * // The background. Note that this has to be composed after Content() so that it
+ * // is measured after it. We set its zIndex to -1 so that it is still placed
+ * // (drawn) before/below it. We don't use BoxScope.matchParentSize() because it
+ * // does not play well with Modifier.element().
+ * Box(
+ * Modifier.zIndex(-1f)
+ * .element(Background)
+ * // Set the preferred size of this element.
+ * // Important: This must be *after* the Modifier.element() so that
+ * // Modifier.element() can override the size.
+ * .sizeMatcherDestination(sizeMatcher)
+ * .background(
+ * MaterialTheme.colorScheme.primaryContainer,
+ * RoundedCornerShape(32.dp),
+ * )
+ * )
+ * }
+ * ```
+ *
+ * @see sizeMatcherSource
+ * @see sizeMatcherDestination
+ */
+class SizeMatcher {
+ internal var source: LayoutModifierNode? = null
+ set(value) {
+ if (value != null && field != null && value != field) {
+ error("Exactly one Modifier.sizeMatcherSource() should be specified")
+ }
+ }
+
+ internal var destinations = mutableSetOf<LayoutModifierNode>()
+ internal var sourceSize: IntSize = InvalidSize
+ get() {
+ if (field == InvalidSize) {
+ error(
+ "SizeMatcher size was retrieved before it was set. You should make sure that " +
+ "all matcher destination are measured *after* the matcher source."
+ )
+ }
+ return field
+ }
+ set(value) {
+ if (value != field) {
+ field = value
+ destinations.forEach { it.invalidateMeasurement() }
+ }
+ }
+
+ companion object {
+ private val InvalidSize = IntSize(Int.MIN_VALUE, Int.MIN_VALUE)
+ }
+}
+
+/**
+ * Mark this node as the source of a [SizeMatcher].
+ *
+ * Important: There must be only a single source node associated to a [SizeMatcher] and it must be
+ * measured before any destination.
+ */
+fun Modifier.sizeMatcherSource(matcher: SizeMatcher): Modifier {
+ return this.then(SizeMatcherSourceNodeElement(matcher))
+}
+
+/**
+ * Mark this node as the destination of a [SizeMatcher] so that its *preferred* size is the same
+ * size as the source size.
+ *
+ * Important: Destination nodes must be measured *after* the source node, otherwise it might cause
+ * crashes or 1-frame flickers. For most simple layouts (like Box, Row or Column), this usually
+ * means that the destinations nodes must be composed *after* the source node. If doing so is
+ * causing layering issues, you can use `Modifier.zIndex` to explicitly set the placement order of
+ * your composables.
+ */
+fun Modifier.sizeMatcherDestination(matcher: SizeMatcher): Modifier {
+ return this.then(SizeMatcherDestinationElement(matcher))
+}
+
+private data class SizeMatcherSourceNodeElement(
+ private val matcher: SizeMatcher,
+) : ModifierNodeElement<SizeMatcherSourceNode>() {
+ override fun create(): SizeMatcherSourceNode = SizeMatcherSourceNode(matcher)
+
+ override fun update(node: SizeMatcherSourceNode) {
+ node.update(matcher)
+ }
+}
+
+private class SizeMatcherSourceNode(
+ private var matcher: SizeMatcher,
+) : Modifier.Node(), LayoutModifierNode {
+ override fun onAttach() {
+ matcher.source = this
+ }
+
+ override fun onDetach() {
+ matcher.source = null
+ }
+
+ fun update(matcher: SizeMatcher) {
+ val previous = this.matcher
+ this.matcher = matcher
+
+ previous.source = null
+ matcher.source = this
+ }
+
+ override fun MeasureScope.measure(
+ measurable: Measurable,
+ constraints: Constraints
+ ): MeasureResult {
+ return measurable.measure(constraints).run {
+ matcher.sourceSize = IntSize(width, height)
+ layout(width, height) { place(0, 0) }
+ }
+ }
+}
+
+private data class SizeMatcherDestinationElement(
+ private val matcher: SizeMatcher,
+) : ModifierNodeElement<SizeMatcherDestinationNode>() {
+ override fun create(): SizeMatcherDestinationNode = SizeMatcherDestinationNode(matcher)
+
+ override fun update(node: SizeMatcherDestinationNode) {
+ node.update(matcher)
+ }
+}
+
+private class SizeMatcherDestinationNode(
+ private var matcher: SizeMatcher,
+) : Modifier.Node(), LayoutModifierNode {
+ override fun onAttach() {
+ this.matcher.destinations.add(this)
+ }
+
+ override fun onDetach() {
+ this.matcher.destinations.remove(this)
+ }
+
+ fun update(matcher: SizeMatcher) {
+ val previous = this.matcher
+ this.matcher = matcher
+
+ previous.destinations.remove(this)
+ matcher.destinations.add(this)
+ }
+
+ override fun MeasureScope.measure(
+ measurable: Measurable,
+ constraints: Constraints
+ ): MeasureResult {
+ val preferredSize = matcher.sourceSize
+ val preferredConstraints = Constraints.fixed(preferredSize.width, preferredSize.height)
+
+ // Make sure we still respect the incoming constraints.
+ val placeable = measurable.measure(constraints.constrain(preferredConstraints))
+ return layout(placeable.width, placeable.height) { placeable.place(0, 0) }
+ }
+}
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt
index a6e52c2..55a342c 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt
@@ -113,7 +113,8 @@
orientation = draggableHandler.orientation,
topOrLeftBehavior = nestedScrollBehavior,
bottomOrRightBehavior = nestedScrollBehavior,
- isExternalOverscrollGesture = { isExternalOverscrollGesture }
+ isExternalOverscrollGesture = { isExternalOverscrollGesture },
+ pointersInfo = { PointersInfo(pointersDown = 1, startedPosition = Offset.Zero) }
)
.connection
@@ -1214,4 +1215,35 @@
onDragStartedImmediately()
assertTransition(fromScene = SceneA, toScene = SceneB, progress = 50f / 75f)
}
+
+ @Test
+ fun requireFullDistanceSwipe() = runGestureTest {
+ mutableUserActionsA[Swipe.Up] = UserActionResult(SceneB, requiresFullDistanceSwipe = true)
+
+ val controller = onDragStarted(overSlop = up(fractionOfScreen = 0.9f))
+ assertTransition(fromScene = SceneA, toScene = SceneB, progress = 0.9f)
+
+ controller.onDragStopped(velocity = 0f)
+ advanceUntilIdle()
+ assertIdle(SceneA)
+
+ val otherController = onDragStarted(overSlop = up(fractionOfScreen = 1f))
+ assertTransition(fromScene = SceneA, toScene = SceneB, progress = 1f)
+ otherController.onDragStopped(velocity = 0f)
+ advanceUntilIdle()
+ assertIdle(SceneB)
+ }
+
+ @Test
+ fun interceptingTransitionReplacesCurrentTransition() = runGestureTest {
+ val controller = onDragStarted(overSlop = up(fractionOfScreen = 0.5f))
+ val transition = assertThat(layoutState.transitionState).isTransition()
+ controller.onDragStopped(velocity = 0f)
+
+ // Intercept the transition.
+ onDragStartedImmediately()
+ val newTransition = assertThat(layoutState.transitionState).isTransition()
+ assertThat(newTransition).isNotSameInstanceAs(transition)
+ assertThat(newTransition.replacedTransition).isSameInstanceAs(transition)
+ }
}
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt
index a18da73..9646bc2 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt
@@ -731,7 +731,7 @@
onAnimatedFloat = { animatedFloat = it },
)
- val fooElement = rule.onNodeWithTag(TestElements.Foo.testTag, useUnmergedTree = true)
+ val fooElement = rule.onNodeWithTag(TestElements.Foo.testTag)
fooElement.assertTopPositionInRootIsEqualTo(0.dp)
val transition = assertThat(state.transitionState).isTransition()
assertThat(transition).isNotNull()
@@ -811,7 +811,7 @@
}
assertThat(state.transitionState).isIdle()
- val fooElement = rule.onNodeWithTag(TestElements.Foo.testTag, useUnmergedTree = true)
+ val fooElement = rule.onNodeWithTag(TestElements.Foo.testTag)
fooElement.assertTopPositionInRootIsEqualTo(0.dp)
// Swipe by half of verticalSwipeDistance.
@@ -839,6 +839,80 @@
}
@Test
+ fun elementTransitionDuringNestedScrollWith2Pointers() {
+ // The draggable touch slop, i.e. the min px distance a touch pointer must move before it is
+ // detected as a drag event.
+ var touchSlop = 0f
+ val translateY = 10.dp
+ val layoutWidth = 200.dp
+ val layoutHeight = 400.dp
+
+ val state =
+ rule.runOnUiThread {
+ MutableSceneTransitionLayoutState(
+ initialScene = SceneA,
+ transitions =
+ transitions {
+ from(SceneA, to = SceneB) {
+ translate(TestElements.Foo, y = translateY)
+ }
+ },
+ )
+ as MutableSceneTransitionLayoutStateImpl
+ }
+
+ rule.setContent {
+ touchSlop = LocalViewConfiguration.current.touchSlop
+ SceneTransitionLayout(
+ state = state,
+ modifier = Modifier.size(layoutWidth, layoutHeight)
+ ) {
+ scene(
+ SceneA,
+ userActions = mapOf(Swipe(SwipeDirection.Down, pointerCount = 2) to SceneB)
+ ) {
+ Box(
+ Modifier
+ // Unconsumed scroll gesture will be intercepted by STL
+ .verticalNestedScrollToScene()
+ // A scrollable that does not consume the scroll gesture
+ .scrollable(
+ rememberScrollableState(consumeScrollDelta = { 0f }),
+ Orientation.Vertical
+ )
+ .fillMaxSize()
+ ) {
+ Spacer(Modifier.element(TestElements.Foo).fillMaxSize())
+ }
+ }
+ scene(SceneB) { Spacer(Modifier.fillMaxSize()) }
+ }
+ }
+
+ assertThat(state.transitionState).isIdle()
+ val fooElement = rule.onNodeWithTag(TestElements.Foo.testTag)
+ fooElement.assertTopPositionInRootIsEqualTo(0.dp)
+
+ // Swipe down with 2 pointers by half of verticalSwipeDistance.
+ rule.onRoot().performTouchInput {
+ val middleTop = Offset((layoutWidth / 2).toPx(), 0f)
+ repeat(2) { i -> down(pointerId = i, middleTop) }
+ repeat(2) { i ->
+ // Scroll 50%
+ moveBy(
+ pointerId = i,
+ delta = Offset(0f, touchSlop + layoutHeight.toPx() * 0.5f),
+ delayMillis = 1_000,
+ )
+ }
+ }
+
+ val transition = assertThat(state.transitionState).isTransition()
+ assertThat(transition).hasProgress(0.5f)
+ fooElement.assertTopPositionInRootIsEqualTo(translateY * 0.5f)
+ }
+
+ @Test
fun elementTransitionWithDistanceDuringOverscroll() {
val layoutWidth = 200.dp
val layoutHeight = 400.dp
@@ -858,7 +932,7 @@
onAnimatedFloat = { animatedFloat = it },
)
- val fooElement = rule.onNodeWithTag(TestElements.Foo.testTag, useUnmergedTree = true)
+ val fooElement = rule.onNodeWithTag(TestElements.Foo.testTag)
fooElement.assertTopPositionInRootIsEqualTo(0.dp)
assertThat(animatedFloat).isEqualTo(100f)
@@ -914,7 +988,7 @@
onAnimatedFloat = { animatedFloat = it },
)
- val fooElement = rule.onNodeWithTag(TestElements.Foo.testTag, useUnmergedTree = true)
+ val fooElement = rule.onNodeWithTag(TestElements.Foo.testTag)
fooElement.assertTopPositionInRootIsEqualTo(0.dp)
assertThat(animatedFloat).isEqualTo(100f)
@@ -1937,4 +2011,119 @@
)
.isEqualTo(Element.SizeUnspecified)
}
+
+ @Test
+ fun transparentElementIsNotImpactingInterruption() = runTest {
+ val state =
+ rule.runOnIdle {
+ MutableSceneTransitionLayoutStateImpl(
+ SceneA,
+ transitions {
+ from(SceneA, to = SceneB) {
+ // In A => B, Foo is not shared and first fades out from A then fades in
+ // B.
+ sharedElement(TestElements.Foo, enabled = false)
+ fractionRange(end = 0.5f) { fade(TestElements.Foo.inScene(SceneA)) }
+ fractionRange(start = 0.5f) { fade(TestElements.Foo.inScene(SceneB)) }
+ }
+
+ from(SceneB, to = SceneA) {
+ // In B => A, Foo is shared.
+ sharedElement(TestElements.Foo, enabled = true)
+ }
+ }
+ )
+ }
+
+ @Composable
+ fun SceneScope.Foo(modifier: Modifier = Modifier) {
+ Box(modifier.element(TestElements.Foo).size(10.dp))
+ }
+
+ rule.setContent {
+ SceneTransitionLayout(state) {
+ scene(SceneB) { Foo(Modifier.offset(40.dp, 60.dp)) }
+
+ // Define A after B so that Foo is placed in A during A <=> B.
+ scene(SceneA) { Foo() }
+ }
+ }
+
+ // Start A => B at 70%.
+ rule.runOnUiThread {
+ state.startTransition(
+ transition(
+ from = SceneA,
+ to = SceneB,
+ progress = { 0.7f },
+ onFinish = neverFinish(),
+ )
+ )
+ }
+
+ rule.onNode(isElement(TestElements.Foo, SceneA)).assertPositionInRootIsEqualTo(0.dp, 0.dp)
+ rule.onNode(isElement(TestElements.Foo, SceneB)).assertPositionInRootIsEqualTo(40.dp, 60.dp)
+
+ // Start B => A at 50% with interruptionProgress = 100%. Foo is placed in A and should still
+ // be at (40dp, 60dp) given that it was fully transparent in A before the interruption.
+ var interruptionProgress by mutableStateOf(1f)
+ rule.runOnUiThread {
+ state.startTransition(
+ transition(
+ from = SceneB,
+ to = SceneA,
+ progress = { 0.5f },
+ interruptionProgress = { interruptionProgress },
+ onFinish = neverFinish(),
+ )
+ )
+ }
+
+ rule.onNode(isElement(TestElements.Foo, SceneA)).assertPositionInRootIsEqualTo(40.dp, 60.dp)
+ rule.onNode(isElement(TestElements.Foo, SceneB)).assertIsNotDisplayed()
+
+ // Set the interruption progress to 0%. Foo should be at (20dp, 30dp) given that B => is at
+ // 50%.
+ interruptionProgress = 0f
+ rule.onNode(isElement(TestElements.Foo, SceneA)).assertPositionInRootIsEqualTo(20.dp, 30.dp)
+ rule.onNode(isElement(TestElements.Foo, SceneB)).assertIsNotDisplayed()
+ }
+
+ @Test
+ fun replacedTransitionDoesNotTriggerInterruption() = runTest {
+ val state = rule.runOnIdle { MutableSceneTransitionLayoutStateImpl(SceneA) }
+
+ @Composable
+ fun SceneScope.Foo(modifier: Modifier = Modifier) {
+ Box(modifier.element(TestElements.Foo).size(10.dp))
+ }
+
+ rule.setContent {
+ SceneTransitionLayout(state) {
+ scene(SceneA) { Foo() }
+ scene(SceneB) { Foo(Modifier.offset(40.dp, 60.dp)) }
+ }
+ }
+
+ // Start A => B at 50%.
+ val aToB1 =
+ transition(from = SceneA, to = SceneB, progress = { 0.5f }, onFinish = neverFinish())
+ rule.runOnUiThread { state.startTransition(aToB1) }
+ rule.onNode(isElement(TestElements.Foo, SceneA)).assertIsNotDisplayed()
+ rule.onNode(isElement(TestElements.Foo, SceneB)).assertPositionInRootIsEqualTo(20.dp, 30.dp)
+
+ // Replace A => B by another A => B at 100%. Even with interruption progress at 100%, Foo
+ // should be at (40dp, 60dp) given that aToB1 was replaced by aToB2.
+ val aToB2 =
+ transition(
+ from = SceneA,
+ to = SceneB,
+ progress = { 1f },
+ interruptionProgress = { 1f },
+ replacedTransition = aToB1,
+ )
+ rule.runOnUiThread { state.startTransition(aToB2) }
+ rule.onNode(isElement(TestElements.Foo, SceneA)).assertIsNotDisplayed()
+ rule.onNode(isElement(TestElements.Foo, SceneB)).assertPositionInRootIsEqualTo(40.dp, 60.dp)
+ }
}
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/InterruptionHandlerTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/InterruptionHandlerTest.kt
index 09d1a82..3552d3d 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/InterruptionHandlerTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/InterruptionHandlerTest.kt
@@ -131,10 +131,6 @@
assertThat(state.currentTransitions)
.comparingElementsUsing(FromToCurrentTriple)
.containsExactly(
- // Initial transition A to B. This transition will never be consumed by anyone given
- // that it has the same (from, to) pair as the next transition.
- Triple(SceneA, SceneB, SceneB),
-
// Initial transition reversed, B back to A.
Triple(SceneA, SceneB, SceneA),
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/Transition.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/Transition.kt
index 322b035..65f4f9e 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/Transition.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/Transition.kt
@@ -37,8 +37,11 @@
bouncingScene: SceneKey? = null,
orientation: Orientation = Orientation.Horizontal,
onFinish: ((TransitionState.Transition) -> Job)? = null,
+ replacedTransition: TransitionState.Transition? = null,
): TransitionState.Transition {
- return object : TransitionState.Transition(from, to), TransitionState.HasOverscrollProperties {
+ return object :
+ TransitionState.Transition(from, to, replacedTransition),
+ TransitionState.HasOverscrollProperties {
override val currentScene: SceneKey
get() = current()
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/modifiers/SizeMatcherTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/modifiers/SizeMatcherTest.kt
new file mode 100644
index 0000000..fa24966
--- /dev/null
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/modifiers/SizeMatcherTest.kt
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.compose.animation.scene.modifiers
+
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.size
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithTag
+import androidx.compose.ui.unit.DpSize
+import androidx.compose.ui.unit.dp
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.compose.test.assertSizeIsEqualTo
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class SizeMatcherTest {
+ @get:Rule val rule = createComposeRule()
+
+ @Test
+ fun sizeMatcher() {
+ val contentSize = DpSize(200.dp, 100.dp)
+ val sizeMatcher = SizeMatcher()
+ val backgroundTag = "background"
+
+ rule.setContent {
+ Box {
+ Box(Modifier.sizeMatcherSource(sizeMatcher).size(contentSize))
+ Box(Modifier.testTag(backgroundTag).sizeMatcherDestination(sizeMatcher))
+ }
+ }
+
+ rule.onNodeWithTag(backgroundTag).assertSizeIsEqualTo(contentSize.width, contentSize.height)
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractorTest.kt
index 3035481..68cfa28 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractorTest.kt
@@ -29,7 +29,6 @@
import com.android.systemui.bouncer.data.repository.keyguardBouncerRepository
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.deviceentry.domain.interactor.deviceUnlockedInteractor
-import com.android.systemui.deviceentry.shared.DeviceEntryUdfpsRefactor
import com.android.systemui.flags.DisableSceneContainer
import com.android.systemui.flags.EnableSceneContainer
import com.android.systemui.keyguard.data.repository.biometricSettingsRepository
@@ -223,23 +222,14 @@
}
private fun givenAlternateBouncerSupported() {
- if (DeviceEntryUdfpsRefactor.isEnabled) {
- kosmos.fingerprintPropertyRepository.supportsUdfps()
- } else {
- kosmos.keyguardBouncerRepository.setAlternateBouncerUIAvailable(true)
- }
+ kosmos.givenAlternateBouncerSupported()
}
private fun givenCanShowAlternateBouncer() {
- givenAlternateBouncerSupported()
- kosmos.keyguardBouncerRepository.setPrimaryShow(false)
- kosmos.biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(true)
- kosmos.biometricSettingsRepository.setIsFingerprintAuthCurrentlyAllowed(true)
- whenever(kosmos.keyguardUpdateMonitor.isFingerprintLockedOut).thenReturn(false)
- whenever(kosmos.keyguardStateController.isUnlocked).thenReturn(false)
+ kosmos.givenCanShowAlternateBouncer()
}
private fun givenCannotShowAlternateBouncer() {
- kosmos.biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(false)
+ kosmos.givenCannotShowAlternateBouncer()
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalPrefsRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalPrefsRepositoryImplTest.kt
index 5e120b5..a8bdc7c 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalPrefsRepositoryImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalPrefsRepositoryImplTest.kt
@@ -18,8 +18,8 @@
import android.content.Context
import android.content.Intent
-import android.content.SharedPreferences
import android.content.pm.UserInfo
+import android.content.pm.UserInfo.FLAG_MAIN
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
@@ -30,108 +30,87 @@
import com.android.systemui.kosmos.testDispatcher
import com.android.systemui.kosmos.testScope
import com.android.systemui.log.logcatLogBuffer
-import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.settings.UserFileManager
+import com.android.systemui.settings.fakeUserFileManager
import com.android.systemui.testKosmos
-import com.android.systemui.user.data.repository.FakeUserRepository
-import com.android.systemui.user.data.repository.fakeUserRepository
-import com.android.systemui.util.FakeSharedPreferences
import com.google.common.truth.Truth.assertThat
-import java.io.File
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
-import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-import org.mockito.Mock
-import org.mockito.Mockito
import org.mockito.Mockito.atLeastOnce
import org.mockito.Mockito.clearInvocations
import org.mockito.Mockito.verify
-import org.mockito.MockitoAnnotations
+import org.mockito.kotlin.spy
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@RunWith(AndroidJUnit4::class)
class CommunalPrefsRepositoryImplTest : SysuiTestCase() {
- @Mock private lateinit var tableLogBuffer: TableLogBuffer
-
- private lateinit var underTest: CommunalPrefsRepositoryImpl
-
private val kosmos = testKosmos()
private val testScope = kosmos.testScope
- private lateinit var userRepository: FakeUserRepository
- private lateinit var userFileManager: UserFileManager
+ private val userFileManager: UserFileManager = spy(kosmos.fakeUserFileManager)
- @Before
- fun setUp() {
- MockitoAnnotations.initMocks(this)
-
- userRepository = kosmos.fakeUserRepository
- userRepository.setUserInfos(USER_INFOS)
-
- userFileManager =
- FakeUserFileManager(
- mapOf(
- USER_INFOS[0].id to FakeSharedPreferences(),
- USER_INFOS[1].id to FakeSharedPreferences()
- )
- )
+ private val underTest: CommunalPrefsRepositoryImpl by lazy {
+ CommunalPrefsRepositoryImpl(
+ kosmos.testDispatcher,
+ userFileManager,
+ kosmos.broadcastDispatcher,
+ logcatLogBuffer("CommunalPrefsRepositoryImplTest"),
+ )
}
@Test
fun isCtaDismissedValue_byDefault_isFalse() =
testScope.runTest {
- underTest = createCommunalPrefsRepositoryImpl(userFileManager)
- val isCtaDismissed by collectLastValue(underTest.isCtaDismissed)
+ val isCtaDismissed by collectLastValue(underTest.isCtaDismissed(MAIN_USER))
assertThat(isCtaDismissed).isFalse()
}
@Test
fun isCtaDismissedValue_onSet_isTrue() =
testScope.runTest {
- underTest = createCommunalPrefsRepositoryImpl(userFileManager)
- val isCtaDismissed by collectLastValue(underTest.isCtaDismissed)
+ val isCtaDismissed by collectLastValue(underTest.isCtaDismissed(MAIN_USER))
- underTest.setCtaDismissedForCurrentUser()
+ underTest.setCtaDismissed(MAIN_USER)
assertThat(isCtaDismissed).isTrue()
}
@Test
- fun isCtaDismissedValue_whenSwitchUser() =
+ fun isCtaDismissedValue_onSetForDifferentUser_isStillFalse() =
testScope.runTest {
- underTest = createCommunalPrefsRepositoryImpl(userFileManager)
- val isCtaDismissed by collectLastValue(underTest.isCtaDismissed)
- underTest.setCtaDismissedForCurrentUser()
+ val isCtaDismissed by collectLastValue(underTest.isCtaDismissed(MAIN_USER))
- // dismissed true for primary user
- assertThat(isCtaDismissed).isTrue()
-
- // switch to secondary user
- userRepository.setSelectedUserInfo(USER_INFOS[1])
-
- // dismissed is false for secondary user
+ underTest.setCtaDismissed(SECONDARY_USER)
assertThat(isCtaDismissed).isFalse()
+ }
- // switch back to primary user
- userRepository.setSelectedUserInfo(USER_INFOS[0])
+ @Test
+ fun isDisclaimerDismissed_byDefault_isFalse() =
+ testScope.runTest {
+ val isDisclaimerDismissed by
+ collectLastValue(underTest.isDisclaimerDismissed(MAIN_USER))
+ assertThat(isDisclaimerDismissed).isFalse()
+ }
- // dismissed is true for primary user
- assertThat(isCtaDismissed).isTrue()
+ @Test
+ fun isDisclaimerDismissed_onSet_isTrue() =
+ testScope.runTest {
+ val isDisclaimerDismissed by
+ collectLastValue(underTest.isDisclaimerDismissed(MAIN_USER))
+
+ underTest.setDisclaimerDismissed(MAIN_USER)
+ assertThat(isDisclaimerDismissed).isTrue()
}
@Test
fun getSharedPreferences_whenFileRestored() =
testScope.runTest {
- val userFileManagerSpy = Mockito.spy(userFileManager)
- underTest = createCommunalPrefsRepositoryImpl(userFileManagerSpy)
-
- val isCtaDismissed by collectLastValue(underTest.isCtaDismissed)
- userRepository.setSelectedUserInfo(USER_INFOS[0])
+ val isCtaDismissed by collectLastValue(underTest.isCtaDismissed(MAIN_USER))
assertThat(isCtaDismissed).isFalse()
- clearInvocations(userFileManagerSpy)
+ clearInvocations(userFileManager)
// Received restore finished event.
kosmos.broadcastDispatcher.sendIntentToMatchingReceiversOnly(
@@ -141,48 +120,12 @@
runCurrent()
// Get shared preferences from the restored file.
- verify(userFileManagerSpy, atLeastOnce())
- .getSharedPreferences(
- FILE_NAME,
- Context.MODE_PRIVATE,
- userRepository.getSelectedUserInfo().id
- )
+ verify(userFileManager, atLeastOnce())
+ .getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE, MAIN_USER.id)
}
- private fun createCommunalPrefsRepositoryImpl(userFileManager: UserFileManager) =
- CommunalPrefsRepositoryImpl(
- testScope.backgroundScope,
- kosmos.testDispatcher,
- userRepository,
- userFileManager,
- kosmos.broadcastDispatcher,
- logcatLogBuffer("CommunalPrefsRepositoryImplTest"),
- tableLogBuffer,
- )
-
- private class FakeUserFileManager(private val sharedPrefs: Map<Int, SharedPreferences>) :
- UserFileManager {
- override fun getFile(fileName: String, userId: Int): File {
- throw UnsupportedOperationException()
- }
-
- override fun getSharedPreferences(
- fileName: String,
- mode: Int,
- userId: Int
- ): SharedPreferences {
- if (fileName != FILE_NAME) {
- throw IllegalArgumentException("Preference files must be $FILE_NAME")
- }
- return sharedPrefs.getValue(userId)
- }
- }
-
companion object {
- val USER_INFOS =
- listOf(
- UserInfo(/* id= */ 0, "zero", /* flags= */ 0),
- UserInfo(/* id= */ 1, "secondary", /* flags= */ 0),
- )
+ val MAIN_USER = UserInfo(0, "main", FLAG_MAIN)
+ val SECONDARY_USER = UserInfo(1, "secondary", 0)
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt
index 3d454a2..d951cca 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt
@@ -488,8 +488,16 @@
@Test
fun ctaTile_afterDismiss_doesNotShow() =
testScope.runTest {
+ // Set to main user, so we can dismiss the tile for the main user.
+ val user = userRepository.asMainUser()
+ userTracker.set(
+ userInfos = listOf(user),
+ selectedUserIndex = 0,
+ )
+ runCurrent()
+
tutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED)
- communalPrefsRepository.setCtaDismissedForCurrentUser()
+ communalPrefsRepository.setCtaDismissed(user)
val ctaTileContent by collectLastValue(underTest.ctaTileContent)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalPrefsInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalPrefsInteractorTest.kt
new file mode 100644
index 0000000..7b79d28
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalPrefsInteractorTest.kt
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.communal.domain.interactor
+
+import android.content.pm.UserInfo
+import android.content.pm.UserInfo.FLAG_MAIN
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.settings.fakeUserTracker
+import com.android.systemui.testKosmos
+import com.android.systemui.user.data.repository.fakeUserRepository
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class CommunalPrefsInteractorTest : SysuiTestCase() {
+
+ private val kosmos = testKosmos()
+ private val testScope = kosmos.testScope
+
+ private val underTest by lazy { kosmos.communalPrefsInteractor }
+
+ @Test
+ fun setCtaDismissed_currentUser() =
+ testScope.runTest {
+ setSelectedUser(MAIN_USER)
+ val isCtaDismissed by collectLastValue(underTest.isCtaDismissed)
+
+ assertThat(isCtaDismissed).isFalse()
+ underTest.setCtaDismissed(MAIN_USER)
+ assertThat(isCtaDismissed).isTrue()
+ }
+
+ @Test
+ fun setCtaDismissed_anotherUser() =
+ testScope.runTest {
+ setSelectedUser(MAIN_USER)
+ val isCtaDismissed by collectLastValue(underTest.isCtaDismissed)
+
+ assertThat(isCtaDismissed).isFalse()
+ underTest.setCtaDismissed(SECONDARY_USER)
+ assertThat(isCtaDismissed).isFalse()
+ }
+
+ @Test
+ fun isCtaDismissed_userSwitch() =
+ testScope.runTest {
+ setSelectedUser(MAIN_USER)
+ underTest.setCtaDismissed(MAIN_USER)
+ val isCtaDismissed by collectLastValue(underTest.isCtaDismissed)
+
+ assertThat(isCtaDismissed).isTrue()
+ setSelectedUser(SECONDARY_USER)
+ assertThat(isCtaDismissed).isFalse()
+ }
+
+ @Test
+ fun setDisclaimerDismissed_currentUser() =
+ testScope.runTest {
+ setSelectedUser(MAIN_USER)
+ val isDisclaimerDismissed by collectLastValue(underTest.isDisclaimerDismissed)
+
+ assertThat(isDisclaimerDismissed).isFalse()
+ underTest.setDisclaimerDismissed(MAIN_USER)
+ assertThat(isDisclaimerDismissed).isTrue()
+ }
+
+ @Test
+ fun setDisclaimerDismissed_anotherUser() =
+ testScope.runTest {
+ setSelectedUser(MAIN_USER)
+ val isDisclaimerDismissed by collectLastValue(underTest.isDisclaimerDismissed)
+
+ assertThat(isDisclaimerDismissed).isFalse()
+ underTest.setDisclaimerDismissed(SECONDARY_USER)
+ assertThat(isDisclaimerDismissed).isFalse()
+ }
+
+ @Test
+ fun isDisclaimerDismissed_userSwitch() =
+ testScope.runTest {
+ setSelectedUser(MAIN_USER)
+ underTest.setDisclaimerDismissed(MAIN_USER)
+ val isDisclaimerDismissed by collectLastValue(underTest.isDisclaimerDismissed)
+
+ assertThat(isDisclaimerDismissed).isTrue()
+ setSelectedUser(SECONDARY_USER)
+ assertThat(isDisclaimerDismissed).isFalse()
+ }
+
+ private suspend fun setSelectedUser(user: UserInfo) {
+ with(kosmos.fakeUserRepository) {
+ setUserInfos(listOf(user))
+ setSelectedUserInfo(user)
+ }
+ kosmos.fakeUserTracker.set(userInfos = listOf(user), selectedUserIndex = 0)
+ }
+
+ private companion object {
+ val MAIN_USER = UserInfo(0, "main", FLAG_MAIN)
+ val SECONDARY_USER = UserInfo(1, "secondary", 0)
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt
index d5fe2a1..0190ccb 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt
@@ -40,6 +40,7 @@
import com.android.systemui.communal.data.repository.fakeCommunalWidgetRepository
import com.android.systemui.communal.domain.interactor.CommunalSceneInteractor
import com.android.systemui.communal.domain.interactor.communalInteractor
+import com.android.systemui.communal.domain.interactor.communalPrefsInteractor
import com.android.systemui.communal.domain.interactor.communalSceneInteractor
import com.android.systemui.communal.domain.interactor.communalSettingsInteractor
import com.android.systemui.communal.domain.model.CommunalContentModel
@@ -48,6 +49,8 @@
import com.android.systemui.communal.shared.model.EditModeState
import com.android.systemui.communal.ui.viewmodel.CommunalEditModeViewModel
import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.flags.Flags
+import com.android.systemui.flags.fakeFeatureFlagsClassic
import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor
import com.android.systemui.kosmos.testDispatcher
import com.android.systemui.kosmos.testScope
@@ -57,6 +60,7 @@
import com.android.systemui.smartspace.data.repository.FakeSmartspaceRepository
import com.android.systemui.smartspace.data.repository.fakeSmartspaceRepository
import com.android.systemui.testKosmos
+import com.android.systemui.user.data.repository.fakeUserRepository
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
@@ -104,10 +108,12 @@
smartspaceRepository = kosmos.fakeSmartspaceRepository
mediaRepository = kosmos.fakeCommunalMediaRepository
communalSceneInteractor = kosmos.communalSceneInteractor
+ kosmos.fakeUserRepository.setUserInfos(listOf(MAIN_USER_INFO))
kosmos.fakeUserTracker.set(
userInfos = listOf(MAIN_USER_INFO),
selectedUserIndex = 0,
)
+ kosmos.fakeFeatureFlagsClassic.set(Flags.COMMUNAL_SERVICE_ENABLED, true)
whenever(providerInfo.profile).thenReturn(UserHandle(MAIN_USER_INFO.id))
underTest =
@@ -120,6 +126,7 @@
uiEventLogger,
logcatLogBuffer("CommunalEditModeViewModelTest"),
kosmos.testDispatcher,
+ kosmos.communalPrefsInteractor,
)
}
@@ -312,6 +319,29 @@
}
}
+ @Test
+ fun showDisclaimer_trueAfterEditModeShowing() =
+ testScope.runTest {
+ val showDisclaimer by collectLastValue(underTest.showDisclaimer)
+
+ assertThat(showDisclaimer).isFalse()
+ underTest.setEditModeState(EditModeState.SHOWING)
+ assertThat(showDisclaimer).isTrue()
+ }
+
+ @Test
+ fun showDisclaimer_falseWhenDismissed() =
+ testScope.runTest {
+ underTest.setEditModeState(EditModeState.SHOWING)
+ kosmos.fakeUserRepository.setSelectedUserInfo(MAIN_USER_INFO)
+
+ val showDisclaimer by collectLastValue(underTest.showDisclaimer)
+
+ assertThat(showDisclaimer).isTrue()
+ underTest.onDisclaimerDismissed()
+ assertThat(showDisclaimer).isFalse()
+ }
+
private companion object {
val MAIN_USER_INFO = UserInfo(0, "primary", UserInfo.FLAG_MAIN)
const val WIDGET_PICKER_PACKAGE_NAME = "widget_picker_package_name"
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt
index e7a7b15..7a5f81c 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt
@@ -100,7 +100,6 @@
@RunWith(ParameterizedAndroidJunit4::class)
class CommunalViewModelTest(flags: FlagsParameterization) : SysuiTestCase() {
@Mock private lateinit var mediaHost: MediaHost
- @Mock private lateinit var user: UserInfo
@Mock private lateinit var providerInfo: AppWidgetProviderInfo
private val kosmos = testKosmos()
@@ -315,6 +314,7 @@
@Test
fun dismissCta_hidesCtaTileAndShowsPopup_thenHidesPopupAfterTimeout() =
testScope.runTest {
+ setIsMainUser(true)
tutorialRepository.setTutorialSettingState(Settings.Secure.HUB_MODE_TUTORIAL_COMPLETED)
val communalContent by collectLastValue(underTest.communalContent)
@@ -338,6 +338,7 @@
@Test
fun popup_onDismiss_hidesImmediately() =
testScope.runTest {
+ setIsMainUser(true)
tutorialRepository.setTutorialSettingState(Settings.Secure.HUB_MODE_TUTORIAL_COMPLETED)
val currentPopup by collectLastValue(underTest.currentPopup)
@@ -743,13 +744,17 @@
}
private suspend fun setIsMainUser(isMainUser: Boolean) {
- whenever(user.isMain).thenReturn(isMainUser)
- userRepository.setUserInfos(listOf(user))
- userRepository.setSelectedUserInfo(user)
+ val user = if (isMainUser) MAIN_USER_INFO else SECONDARY_USER_INFO
+ with(userRepository) {
+ setUserInfos(listOf(user))
+ setSelectedUserInfo(user)
+ }
+ kosmos.fakeUserTracker.set(userInfos = listOf(user), selectedUserIndex = 0)
}
private companion object {
val MAIN_USER_INFO = UserInfo(0, "primary", UserInfo.FLAG_MAIN)
+ val SECONDARY_USER_INFO = UserInfo(1, "secondary", 0)
@JvmStatic
@Parameters(name = "{0}")
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractorTest.kt
index d20fec4..5115f5a 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractorTest.kt
@@ -90,7 +90,11 @@
)
reset(transitionRepository)
+ kosmos.fakeKeyguardBouncerRepository.setKeyguardAuthenticatedBiometrics(null)
kosmos.fakeKeyguardRepository.setKeyguardOccluded(true)
+ runCurrent()
+ assertThat(transitionRepository).noTransitionsStarted()
+
kosmos.fakeKeyguardBouncerRepository.setKeyguardAuthenticatedBiometrics(true)
runCurrent()
kosmos.fakeKeyguardBouncerRepository.setKeyguardAuthenticatedBiometrics(null)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModelTest.kt
index 6d9c271..b49e546 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModelTest.kt
@@ -227,6 +227,15 @@
assertThat(accessibilityDelegateHint)
.isEqualTo(DeviceEntryIconView.AccessibilityHintType.BOUNCER)
+ // udfps running
+ setUpState(
+ isUdfpsSupported = true,
+ isUdfpsRunning = true,
+ )
+
+ assertThat(accessibilityDelegateHint)
+ .isEqualTo(DeviceEntryIconView.AccessibilityHintType.BOUNCER)
+
// non-interactive lock icon
fingerprintPropertyRepository.supportsRearFps()
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/data/repository/MediaFilterRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/data/repository/MediaFilterRepositoryTest.kt
index bc0512a..f43fa50 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/data/repository/MediaFilterRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/data/repository/MediaFilterRepositoryTest.kt
@@ -30,11 +30,21 @@
import com.android.systemui.media.controls.shared.model.MediaDataLoadingModel
import com.android.systemui.media.controls.shared.model.SmartspaceMediaData
import com.android.systemui.media.controls.shared.model.SmartspaceMediaLoadingModel
+import com.android.systemui.media.controls.util.SmallHash
+import com.android.systemui.media.controls.util.mediaSmartspaceLogger
+import com.android.systemui.media.controls.util.mockMediaSmartspaceLogger
import com.android.systemui.testKosmos
+import com.android.systemui.util.time.systemClock
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.test.runTest
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.anyBoolean
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.ArgumentMatchers.eq
+import org.mockito.kotlin.never
+import org.mockito.kotlin.reset
+import org.mockito.kotlin.verify
@SmallTest
@RunWith(AndroidJUnit4::class)
@@ -42,8 +52,20 @@
private val kosmos = testKosmos()
private val testScope = kosmos.testScope
+ private val smartspaceLogger = kosmos.mockMediaSmartspaceLogger
+ private val icon = Icon.createWithResource(context, R.drawable.ic_media_play)
+ private val mediaRecommendation =
+ SmartspaceMediaData(
+ targetId = KEY_MEDIA_SMARTSPACE,
+ isActive = true,
+ recommendations = MediaTestHelper.getValidRecommendationList(icon),
+ )
- private val underTest: MediaFilterRepository = kosmos.mediaFilterRepository
+ private val underTest: MediaFilterRepository =
+ with(kosmos) {
+ mediaSmartspaceLogger = mockMediaSmartspaceLogger
+ mediaFilterRepository
+ }
@Test
fun addSelectedUserMediaEntry_activeThenInactivate() =
@@ -137,14 +159,6 @@
testScope.runTest {
val smartspaceMediaData by collectLastValue(underTest.smartspaceMediaData)
- val icon = Icon.createWithResource(context, R.drawable.ic_media_play)
- val mediaRecommendation =
- SmartspaceMediaData(
- targetId = KEY_MEDIA_SMARTSPACE,
- isActive = true,
- recommendations = MediaTestHelper.getValidRecommendationList(icon),
- )
-
underTest.setRecommendation(mediaRecommendation)
assertThat(smartspaceMediaData).isEqualTo(mediaRecommendation)
@@ -164,16 +178,38 @@
val playingData = createMediaData("app1", true, LOCAL, false, playingInstanceId)
val remoteData = createMediaData("app2", true, REMOTE, false, remoteInstanceId)
+ underTest.setRecommendation(mediaRecommendation)
+ underTest.setRecommendationsLoadingState(
+ SmartspaceMediaLoadingModel.Loaded(KEY_MEDIA_SMARTSPACE, true)
+ )
underTest.addSelectedUserMediaEntry(playingData)
underTest.addMediaDataLoadingState(MediaDataLoadingModel.Loaded(playingInstanceId))
+
+ verify(smartspaceLogger)
+ .logSmartspaceCardReceived(
+ playingData.smartspaceId,
+ playingData.appUid,
+ cardinality = 2
+ )
+
underTest.addSelectedUserMediaEntry(remoteData)
underTest.addMediaDataLoadingState(MediaDataLoadingModel.Loaded(remoteInstanceId))
- assertThat(currentMedia?.size).isEqualTo(2)
+ verify(smartspaceLogger)
+ .logSmartspaceCardReceived(
+ remoteData.smartspaceId,
+ playingData.appUid,
+ cardinality = 3,
+ rank = 1
+ )
+ assertThat(currentMedia?.size).isEqualTo(3)
assertThat(currentMedia)
.containsExactly(
MediaCommonModel.MediaControl(MediaDataLoadingModel.Loaded(playingInstanceId)),
- MediaCommonModel.MediaControl(MediaDataLoadingModel.Loaded(remoteInstanceId))
+ MediaCommonModel.MediaControl(MediaDataLoadingModel.Loaded(remoteInstanceId)),
+ MediaCommonModel.MediaRecommendations(
+ SmartspaceMediaLoadingModel.Loaded(KEY_MEDIA_SMARTSPACE, true)
+ )
)
.inOrder()
}
@@ -222,6 +258,16 @@
underTest.setOrderedMedia()
+ verify(smartspaceLogger, never())
+ .logSmartspaceCardReceived(
+ anyInt(),
+ anyInt(),
+ anyInt(),
+ anyBoolean(),
+ anyBoolean(),
+ anyInt(),
+ anyInt()
+ )
assertThat(currentMedia?.size).isEqualTo(2)
assertThat(currentMedia)
.containsExactly(
@@ -248,14 +294,6 @@
val stoppedAndRemoteData = createMediaData("app4", false, REMOTE, false, instanceId4)
val canResumeData = createMediaData("app5", false, LOCAL, true, instanceId5)
- val icon = Icon.createWithResource(context, R.drawable.ic_media_play)
- val mediaRecommendations =
- SmartspaceMediaData(
- targetId = KEY_MEDIA_SMARTSPACE,
- isActive = true,
- recommendations = MediaTestHelper.getValidRecommendationList(icon),
- )
-
underTest.addSelectedUserMediaEntry(stoppedAndLocalData)
underTest.addMediaDataLoadingState(MediaDataLoadingModel.Loaded(instanceId3))
@@ -271,11 +309,33 @@
underTest.addSelectedUserMediaEntry(playingAndRemoteData)
underTest.addMediaDataLoadingState(MediaDataLoadingModel.Loaded(instanceId2))
- underTest.setRecommendation(mediaRecommendations)
+ underTest.setRecommendation(mediaRecommendation)
underTest.setRecommendationsLoadingState(
SmartspaceMediaLoadingModel.Loaded(KEY_MEDIA_SMARTSPACE, true)
)
+ underTest.setOrderedMedia()
+ val smartspaceId = SmallHash.hash(mediaRecommendation.targetId)
+ verify(smartspaceLogger)
+ .logSmartspaceCardReceived(
+ eq(smartspaceId),
+ anyInt(),
+ eq(6),
+ anyBoolean(),
+ anyBoolean(),
+ eq(2),
+ anyInt()
+ )
+ verify(smartspaceLogger, never())
+ .logSmartspaceCardReceived(
+ eq(playingAndLocalData.smartspaceId),
+ anyInt(),
+ anyInt(),
+ anyBoolean(),
+ anyBoolean(),
+ anyInt(),
+ anyInt()
+ )
assertThat(currentMedia?.size).isEqualTo(6)
assertThat(currentMedia)
.containsExactly(
@@ -312,18 +372,10 @@
isPlaying = true,
notificationKey = KEY_2
)
- val icon = Icon.createWithResource(context, R.drawable.ic_media_play)
- val mediaRecommendations =
- SmartspaceMediaData(
- targetId = KEY_MEDIA_SMARTSPACE,
- isActive = true,
- packageName = PACKAGE_NAME,
- recommendations = MediaTestHelper.getValidRecommendationList(icon),
- )
underTest.setMediaFromRecPackageName(PACKAGE_NAME)
underTest.addSelectedUserMediaEntry(data)
- underTest.setRecommendation(mediaRecommendations)
+ underTest.setRecommendation(mediaRecommendation)
underTest.setRecommendationsLoadingState(
SmartspaceMediaLoadingModel.Loaded(KEY_MEDIA_SMARTSPACE)
)
@@ -365,6 +417,88 @@
fun hasActiveMedia_noMediaSet_returnsFalse() =
testScope.runTest { assertThat(underTest.hasActiveMedia()).isFalse() }
+ @Test
+ fun updateMediaWithLatency_smartspaceIsLogged() =
+ testScope.runTest {
+ val instanceId = InstanceId.fakeInstanceId(123)
+ val data = createMediaData("app", true, LOCAL, false, instanceId)
+
+ underTest.setRecommendation(mediaRecommendation)
+ underTest.setRecommendationsLoadingState(
+ SmartspaceMediaLoadingModel.Loaded(KEY_MEDIA_SMARTSPACE, true)
+ )
+
+ val smartspaceId = SmallHash.hash(mediaRecommendation.targetId)
+ verify(smartspaceLogger)
+ .logSmartspaceCardReceived(
+ eq(smartspaceId),
+ anyInt(),
+ eq(1),
+ eq(true),
+ anyBoolean(),
+ eq(0),
+ anyInt()
+ )
+ reset(smartspaceLogger)
+
+ underTest.addSelectedUserMediaEntry(data)
+ underTest.addMediaDataLoadingState(MediaDataLoadingModel.Loaded(instanceId))
+
+ verify(smartspaceLogger)
+ .logSmartspaceCardReceived(data.smartspaceId, data.appUid, cardinality = 2)
+
+ reset(smartspaceLogger)
+
+ underTest.addSelectedUserMediaEntry(data)
+ underTest.addMediaDataLoadingState(
+ MediaDataLoadingModel.Loaded(instanceId, receivedSmartspaceCardLatency = 123)
+ )
+
+ verify(smartspaceLogger)
+ .logSmartspaceCardReceived(
+ SmallHash.hash(data.appUid + kosmos.systemClock.currentTimeMillis().toInt()),
+ data.appUid,
+ cardinality = 2,
+ rank = 0,
+ receivedLatencyMillis = 123
+ )
+ }
+
+ @Test
+ fun resumeMedia_loadSmartspace_allSmartspaceIsLogged() =
+ testScope.runTest {
+ val resumeInstanceId = InstanceId.fakeInstanceId(123)
+ val data = createMediaData("app", false, LOCAL, true, resumeInstanceId)
+
+ underTest.addSelectedUserMediaEntry(data.copy(active = false))
+ underTest.addMediaDataLoadingState(MediaDataLoadingModel.Loaded(resumeInstanceId))
+ underTest.setRecommendation(mediaRecommendation)
+ underTest.setRecommendationsLoadingState(
+ SmartspaceMediaLoadingModel.Loaded(KEY_MEDIA_SMARTSPACE, true)
+ )
+
+ assertThat(underTest.hasActiveMedia()).isFalse()
+ assertThat(underTest.hasAnyMedia()).isTrue()
+ val smartspaceId = SmallHash.hash(mediaRecommendation.targetId)
+ verify(smartspaceLogger)
+ .logSmartspaceCardReceived(
+ eq(smartspaceId),
+ anyInt(),
+ eq(2),
+ eq(true),
+ anyBoolean(),
+ eq(0),
+ anyInt()
+ )
+ verify(smartspaceLogger)
+ .logSmartspaceCardReceived(
+ SmallHash.hash(data.appUid + kosmos.systemClock.currentTimeMillis().toInt()),
+ data.appUid,
+ cardinality = 2,
+ rank = 1
+ )
+ }
+
private fun createMediaData(
app: String,
playing: Boolean,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/spatial/SpatialAudioComponentKosmos.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/spatial/SpatialAudioComponentKosmos.kt
index 777240c..5826b3f 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/spatial/SpatialAudioComponentKosmos.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/spatial/SpatialAudioComponentKosmos.kt
@@ -17,8 +17,10 @@
package com.android.systemui.volume.panel.component.spatial
import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.backgroundCoroutineContext
import com.android.systemui.kosmos.testScope
import com.android.systemui.media.spatializerInteractor
+import com.android.systemui.volume.data.repository.audioRepository
import com.android.systemui.volume.domain.interactor.audioOutputInteractor
import com.android.systemui.volume.panel.component.spatial.domain.interactor.SpatialAudioComponentInteractor
@@ -27,6 +29,8 @@
SpatialAudioComponentInteractor(
audioOutputInteractor,
spatializerInteractor,
+ audioRepository,
+ backgroundCoroutineContext,
testScope.backgroundScope
)
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/spatial/domain/interactor/SpatialAudioComponentInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/spatial/domain/interactor/SpatialAudioComponentInteractorTest.kt
index c6c46fa..555d77c 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/spatial/domain/interactor/SpatialAudioComponentInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/spatial/domain/interactor/SpatialAudioComponentInteractorTest.kt
@@ -16,14 +16,22 @@
package com.android.systemui.volume.panel.component.spatial.domain.interactor
+import android.bluetooth.BluetoothDevice
+import android.bluetooth.BluetoothProfile
import android.media.AudioDeviceAttributes
import android.media.AudioDeviceInfo
import android.media.session.MediaSession
import android.media.session.PlaybackState
+import android.platform.test.annotations.EnableFlags
+import android.platform.test.flag.junit.SetFlagsRule
import android.testing.TestableLooper
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
+import com.android.settingslib.bluetooth.A2dpProfile
import com.android.settingslib.bluetooth.CachedBluetoothDevice
+import com.android.settingslib.bluetooth.HearingAidProfile
+import com.android.settingslib.bluetooth.LeAudioProfile
+import com.android.settingslib.flags.Flags
import com.android.settingslib.media.BluetoothMediaDevice
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
@@ -44,6 +52,7 @@
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
+import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@@ -52,15 +61,29 @@
@RunWith(AndroidJUnit4::class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
class SpatialAudioComponentInteractorTest : SysuiTestCase() {
+ @get:Rule val setFlagsRule = SetFlagsRule()
private val kosmos = testKosmos()
private lateinit var underTest: SpatialAudioComponentInteractor
+ private val a2dpProfile: A2dpProfile = mock {
+ whenever(profileId).thenReturn(BluetoothProfile.A2DP)
+ }
+ private val leAudioProfile: LeAudioProfile = mock {
+ whenever(profileId).thenReturn(BluetoothProfile.LE_AUDIO)
+ }
+ private val hearingAidProfile: HearingAidProfile = mock {
+ whenever(profileId).thenReturn(BluetoothProfile.HEARING_AID)
+ }
+ private val bluetoothDevice: BluetoothDevice = mock {}
@Before
fun setup() {
with(kosmos) {
val cachedBluetoothDevice: CachedBluetoothDevice = mock {
whenever(address).thenReturn("test_address")
+ whenever(device).thenReturn(bluetoothDevice)
+ whenever(profiles)
+ .thenReturn(listOf(a2dpProfile, leAudioProfile, hearingAidProfile))
}
localMediaRepository.updateCurrentConnectedDevice(
mock<BluetoothMediaDevice> {
@@ -83,7 +106,7 @@
fun setEnabled_changesIsEnabled() {
with(kosmos) {
testScope.runTest {
- spatializerRepository.setIsSpatialAudioAvailable(headset, true)
+ spatializerRepository.setIsSpatialAudioAvailable(bleHeadsetAttributes, true)
val values by collectValues(underTest.isEnabled)
underTest.setEnabled(SpatialAudioEnabledModel.Disabled)
@@ -106,10 +129,39 @@
}
@Test
+ @EnableFlags(Flags.FLAG_ENABLE_DETERMINING_SPATIAL_AUDIO_ATTRIBUTES_BY_PROFILE)
+ fun setEnabled_determinedByBluetoothProfile_a2dpProfileEnabled() {
+ with(kosmos) {
+ testScope.runTest {
+ whenever(a2dpProfile.isEnabled(bluetoothDevice)).thenReturn(true)
+ whenever(leAudioProfile.isEnabled(bluetoothDevice)).thenReturn(false)
+ whenever(hearingAidProfile.isEnabled(bluetoothDevice)).thenReturn(false)
+ spatializerRepository.setIsSpatialAudioAvailable(a2dpAttributes, true)
+ val values by collectValues(underTest.isEnabled)
+
+ underTest.setEnabled(SpatialAudioEnabledModel.Disabled)
+ runCurrent()
+ underTest.setEnabled(SpatialAudioEnabledModel.SpatialAudioEnabled)
+ runCurrent()
+
+ assertThat(values)
+ .containsExactly(
+ SpatialAudioEnabledModel.Unknown,
+ SpatialAudioEnabledModel.Disabled,
+ SpatialAudioEnabledModel.SpatialAudioEnabled,
+ )
+ .inOrder()
+ assertThat(spatializerRepository.getSpatialAudioCompatibleDevices())
+ .containsExactly(a2dpAttributes)
+ }
+ }
+ }
+
+ @Test
fun connectedDeviceSupports_isAvailable_SpatialAudio() {
with(kosmos) {
testScope.runTest {
- spatializerRepository.setIsSpatialAudioAvailable(headset, true)
+ spatializerRepository.setIsSpatialAudioAvailable(bleHeadsetAttributes, true)
val isAvailable by collectLastValue(underTest.isAvailable)
@@ -123,8 +175,8 @@
fun connectedDeviceSupportsHeadTracking_isAvailable_HeadTracking() {
with(kosmos) {
testScope.runTest {
- spatializerRepository.setIsSpatialAudioAvailable(headset, true)
- spatializerRepository.setIsHeadTrackingAvailable(headset, true)
+ spatializerRepository.setIsSpatialAudioAvailable(bleHeadsetAttributes, true)
+ spatializerRepository.setIsHeadTrackingAvailable(bleHeadsetAttributes, true)
val isAvailable by collectLastValue(underTest.isAvailable)
@@ -138,7 +190,7 @@
fun connectedDeviceDoesntSupport_isAvailable_Unavailable() {
with(kosmos) {
testScope.runTest {
- spatializerRepository.setIsSpatialAudioAvailable(headset, false)
+ spatializerRepository.setIsSpatialAudioAvailable(bleHeadsetAttributes, false)
val isAvailable by collectLastValue(underTest.isAvailable)
@@ -179,7 +231,13 @@
}
private companion object {
- val headset =
+ val a2dpAttributes =
+ AudioDeviceAttributes(
+ AudioDeviceAttributes.ROLE_OUTPUT,
+ AudioDeviceInfo.TYPE_BLUETOOTH_A2DP,
+ "test_address"
+ )
+ val bleHeadsetAttributes =
AudioDeviceAttributes(
AudioDeviceAttributes.ROLE_OUTPUT,
AudioDeviceInfo.TYPE_BLE_HEADSET,
diff --git a/packages/SystemUI/res/drawable/placeholder_touchpad_back_gesture.png b/packages/SystemUI/res/drawable/placeholder_touchpad_back_gesture.png
new file mode 100644
index 0000000..526b585
--- /dev/null
+++ b/packages/SystemUI/res/drawable/placeholder_touchpad_back_gesture.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable/placeholder_touchpad_tablet_back_gesture.png b/packages/SystemUI/res/drawable/placeholder_touchpad_tablet_back_gesture.png
new file mode 100644
index 0000000..cba2d20
--- /dev/null
+++ b/packages/SystemUI/res/drawable/placeholder_touchpad_tablet_back_gesture.png
Binary files differ
diff --git a/packages/SystemUI/res/layout/app_clips_screenshot.xml b/packages/SystemUI/res/layout/app_clips_screenshot.xml
index bcc7bca..a3af9490 100644
--- a/packages/SystemUI/res/layout/app_clips_screenshot.xml
+++ b/packages/SystemUI/res/layout/app_clips_screenshot.xml
@@ -51,6 +51,15 @@
app:layout_constraintStart_toEndOf="@id/save"
app:layout_constraintTop_toTopOf="parent" />
+ <TextView
+ android:id="@+id/backlinks_data"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="8dp"
+ android:visibility="gone"
+ app:layout_constraintStart_toEndOf="@id/cancel"
+ app:layout_constraintTop_toTopOf="parent" />
+
<ImageView
android:id="@+id/preview"
android:layout_width="0px"
diff --git a/packages/SystemUI/res/layout/screenshot_shelf.xml b/packages/SystemUI/res/layout/screenshot_shelf.xml
index 84ab0f1..fff1de7 100644
--- a/packages/SystemUI/res/layout/screenshot_shelf.xml
+++ b/packages/SystemUI/res/layout/screenshot_shelf.xml
@@ -51,7 +51,6 @@
android:layout_marginBottom="@dimen/overlay_border_width"
android:layout_gravity="center"
android:elevation="4dp"
- android:contentDescription="@string/screenshot_edit_description"
android:scaleType="fitEnd"
android:background="@drawable/overlay_preview_background"
android:adjustViewBounds="true"
@@ -67,7 +66,6 @@
android:layout_marginBottom="@dimen/overlay_border_width"
android:layout_gravity="center"
android:elevation="4dp"
- android:contentDescription="@string/screenshot_edit_description"
android:scaleType="fitEnd"
android:background="@drawable/overlay_preview_background"
android:adjustViewBounds="true"
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 8381812..abafb01 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -269,6 +269,8 @@
<string name="screenshot_detected_multiple_template"><xliff:g id="appName" example="Google Chrome">%1$s</xliff:g> and other open apps detected this screenshot.</string>
<!-- Add to note button used in App Clips flow to return the saved screenshot image to notes app. [CHAR LIMIT=NONE] -->
<string name="app_clips_save_add_to_note">Add to note</string>
+ <!-- TODO(b/300307759): Temporary string for text view that displays backlinks data. [CHAR LIMIT=NONE] -->
+ <string name="backlinks_string" translatable="false">Open <xliff:g id="appName" example="Google Chrome">%1$s</xliff:g></string>
<!-- Notification title displayed for screen recording [CHAR LIMIT=50]-->
<string name="screenrecord_title">Screen Recorder</string>
@@ -1222,6 +1224,12 @@
<string name="accessibility_action_label_remove_widget">remove widget</string>
<!-- Label for accessibility action to place a widget in edit mode after selecting move widget. [CHAR LIMIT=NONE] -->
<string name="accessibility_action_label_place_widget">place selected widget</string>
+ <!-- Title shown above information regarding lock screen widgets. [CHAR LIMIT=50] -->
+ <string name="communal_widgets_disclaimer_title">Lock screen widgets</string>
+ <!-- Information about lock screen widgets presented to the user. [CHAR LIMIT=NONE] -->
+ <string name="communal_widgets_disclaimer_text">To open an app using a widget, you\u2019ll need to verify it\u2019s you. Also, keep in mind that anyone can view them, even when your tablet\u2019s locked. Some widgets may not have been intended for your lock screen and may be unsafe to add here.</string>
+ <!-- Button for user to verify they understand the information presented. [CHAR LIMIT=50] -->
+ <string name="communal_widgets_disclaimer_button">Got it</string>
<!-- Related to user switcher --><skip/>
@@ -1380,6 +1388,15 @@
<!-- Text which is shown in the expanded notification shade when there are currently no notifications visible that the user hasn't already seen. [CHAR LIMIT=30] -->
<string name="no_unseen_notif_text">No new notifications</string>
+ <!-- Title of heads up notification for adaptive notifications user education. [CHAR LIMIT=30] -->
+ <string name="adaptive_notification_edu_hun_title">Adaptive notifications is on</string>
+
+ <!-- Text of heads up notification for adaptive notifications user education. [CHAR LIMIT=100] -->
+ <string name="adaptive_notification_edu_hun_text">Your device now lowers the volume and reduces pop-ups on the screen for up to two minutes when you receive many notifications in a short time span.</string>
+
+ <!-- Action label for going to adaptive notification settings [CHAR LIMIT=20] -->
+ <string name="go_to_adaptive_notification_settings">Turn off</string>
+
<!-- Text which is shown in the locked notification shade when there are currently no notifications, but if the user were to unlock, notifications would appear. [CHAR LIMIT=40] -->
<string name="unlock_to_see_notif_text">Unlock to see older notifications</string>
@@ -3577,6 +3594,12 @@
<string name="touchpad_tutorial_action_key_button">Action key</string>
<!-- Label for button finishing touchpad tutorial [CHAR LIMIT=NONE] -->
<string name="touchpad_tutorial_done_button">Done</string>
+ <!-- Touchpad back gesture action name in tutorial [CHAR LIMIT=NONE] -->
+ <string name="touchpad_back_gesture_action_title">Go back</string>
+ <!-- Touchpad back gesture guidance in gestures tutorial [CHAR LIMIT=NONE] -->
+ <string name="touchpad_back_gesture_guidance">To go back, swipe left or right using three fingers anywhere on the touchpad.</string>
+ <string name="touchpad_back_gesture_animation_content_description">Touchpad showing three fingers moving right and left</string>
+ <string name="touchpad_back_gesture_screen_animation_content_description">Device screen showing animation for back gesture</string>
<!-- Content description for keyboard backlight brightness dialog [CHAR LIMIT=NONE] -->
<string name="keyboard_backlight_dialog_title">Keyboard backlight</string>
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java b/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java
index 68a69d3..37e9dc1a 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java
@@ -42,6 +42,7 @@
import android.view.KeyEvent;
import android.view.WindowManagerGlobal;
import android.view.accessibility.AccessibilityManager;
+import android.view.accessibility.Flags;
import com.android.internal.R;
import com.android.internal.accessibility.dialog.AccessibilityButtonChooserActivity;
@@ -178,6 +179,18 @@
private static final int SYSTEM_ACTION_ID_DPAD_CENTER =
AccessibilityService.GLOBAL_ACTION_DPAD_CENTER; // 20
+ /**
+ * Action ID to trigger menu key event.
+ */
+ private static final int SYSTEM_ACTION_ID_MENU =
+ AccessibilityService.GLOBAL_ACTION_MENU; // 21
+
+ /**
+ * Action ID to trigger media play/pause key event.
+ */
+ private static final int SYSTEM_ACTION_ID_MEDIA_PLAY_PAUSE =
+ AccessibilityService.GLOBAL_ACTION_MEDIA_PLAY_PAUSE; // 22
+
private static final String PERMISSION_SELF = "com.android.systemui.permission.SELF";
private final SystemActionsBroadcastReceiver mReceiver;
@@ -307,6 +320,14 @@
R.string.accessibility_system_action_dpad_center_label,
SystemActionsBroadcastReceiver.INTENT_ACTION_DPAD_CENTER);
+ RemoteAction actionMenu = createRemoteAction(
+ R.string.accessibility_system_action_menu_label,
+ SystemActionsBroadcastReceiver.INTENT_ACTION_MENU);
+
+ RemoteAction actionMediaPlayPause = createRemoteAction(
+ R.string.accessibility_system_action_media_play_pause_label,
+ SystemActionsBroadcastReceiver.INTENT_ACTION_MEDIA_PLAY_PAUSE);
+
mA11yManager.registerSystemAction(actionBack, SYSTEM_ACTION_ID_BACK);
mA11yManager.registerSystemAction(actionHome, SYSTEM_ACTION_ID_HOME);
mA11yManager.registerSystemAction(actionRecents, SYSTEM_ACTION_ID_RECENTS);
@@ -326,6 +347,8 @@
mA11yManager.registerSystemAction(actionDpadLeft, SYSTEM_ACTION_ID_DPAD_LEFT);
mA11yManager.registerSystemAction(actionDpadRight, SYSTEM_ACTION_ID_DPAD_RIGHT);
mA11yManager.registerSystemAction(actionDpadCenter, SYSTEM_ACTION_ID_DPAD_CENTER);
+ mA11yManager.registerSystemAction(actionMenu, SYSTEM_ACTION_ID_MENU);
+ mA11yManager.registerSystemAction(actionMediaPlayPause, SYSTEM_ACTION_ID_MEDIA_PLAY_PAUSE);
registerOrUnregisterDismissNotificationShadeAction();
}
@@ -435,6 +458,14 @@
labelId = R.string.accessibility_system_action_dpad_center_label;
intent = SystemActionsBroadcastReceiver.INTENT_ACTION_DPAD_CENTER;
break;
+ case SYSTEM_ACTION_ID_MENU:
+ labelId = R.string.accessibility_system_action_menu_label;
+ intent = SystemActionsBroadcastReceiver.INTENT_ACTION_MENU;
+ break;
+ case SYSTEM_ACTION_ID_MEDIA_PLAY_PAUSE:
+ labelId = R.string.accessibility_system_action_media_play_pause_label;
+ intent = SystemActionsBroadcastReceiver.INTENT_ACTION_MEDIA_PLAY_PAUSE;
+ break;
default:
return;
}
@@ -570,6 +601,16 @@
sendDownAndUpKeyEvents(KeyEvent.KEYCODE_DPAD_CENTER);
}
+ @VisibleForTesting
+ void handleMenu() {
+ sendDownAndUpKeyEvents(KeyEvent.KEYCODE_MENU);
+ }
+
+ @VisibleForTesting
+ void handleMediaPlayPause() {
+ sendDownAndUpKeyEvents(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE);
+ }
+
private class SystemActionsBroadcastReceiver extends BroadcastReceiver {
private static final String INTENT_ACTION_BACK = "SYSTEM_ACTION_BACK";
private static final String INTENT_ACTION_HOME = "SYSTEM_ACTION_HOME";
@@ -593,6 +634,9 @@
private static final String INTENT_ACTION_DPAD_LEFT = "SYSTEM_ACTION_DPAD_LEFT";
private static final String INTENT_ACTION_DPAD_RIGHT = "SYSTEM_ACTION_DPAD_RIGHT";
private static final String INTENT_ACTION_DPAD_CENTER = "SYSTEM_ACTION_DPAD_CENTER";
+ private static final String INTENT_ACTION_MENU = "SYSTEM_ACTION_MENU";
+ private static final String INTENT_ACTION_MEDIA_PLAY_PAUSE =
+ "SYSTEM_ACTION_MEDIA_PLAY_PAUSE";
private PendingIntent createPendingIntent(Context context, String intentAction) {
switch (intentAction) {
@@ -613,7 +657,9 @@
case INTENT_ACTION_DPAD_DOWN:
case INTENT_ACTION_DPAD_LEFT:
case INTENT_ACTION_DPAD_RIGHT:
- case INTENT_ACTION_DPAD_CENTER: {
+ case INTENT_ACTION_DPAD_CENTER:
+ case INTENT_ACTION_MENU:
+ case INTENT_ACTION_MEDIA_PLAY_PAUSE: {
Intent intent = new Intent(intentAction);
intent.setPackage(context.getPackageName());
intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
@@ -646,6 +692,8 @@
intentFilter.addAction(INTENT_ACTION_DPAD_LEFT);
intentFilter.addAction(INTENT_ACTION_DPAD_RIGHT);
intentFilter.addAction(INTENT_ACTION_DPAD_CENTER);
+ intentFilter.addAction(INTENT_ACTION_MENU);
+ intentFilter.addAction(INTENT_ACTION_MEDIA_PLAY_PAUSE);
return intentFilter;
}
@@ -725,6 +773,18 @@
handleDpadCenter();
break;
}
+ case INTENT_ACTION_MENU: {
+ if (Flags.globalActionMenu()) {
+ handleMenu();
+ }
+ break;
+ }
+ case INTENT_ACTION_MEDIA_PLAY_PAUSE: {
+ if (Flags.globalActionMediaPlayPause()) {
+ handleMediaPlayPause();
+ }
+ break;
+ }
default:
break;
}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
index 5458ab1..25ad385 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
@@ -1631,8 +1631,23 @@
boolean bRTL = isRTL(mContext);
final int initSize = Math.min(mWindowBounds.width(), mWindowBounds.height()) / 3;
- final int maxHeightSize = mWindowBounds.height() - 2 * mMirrorSurfaceMargin;
- final int maxWidthSize = mWindowBounds.width() - 2 * mMirrorSurfaceMargin;
+ int maxHeightSize;
+ int maxWidthSize;
+ if (Flags.redesignMagnifierWindowSize()) {
+ // mOuterBorderSize = transparent margin area
+ // mMirrorSurfaceMargin = transparent margin area + orange border width
+ // We would like to allow the width and height to be full size. Therefore, the max
+ // frame size could be calculated as (window bounds - 2 * orange border width).
+ maxHeightSize =
+ mWindowBounds.height() - 2 * (mMirrorSurfaceMargin - mOuterBorderSize);
+ maxWidthSize =
+ mWindowBounds.width() - 2 * (mMirrorSurfaceMargin - mOuterBorderSize);
+ } else {
+ maxHeightSize =
+ mWindowBounds.height() - 2 * mMirrorSurfaceMargin;
+ maxWidthSize =
+ mWindowBounds.width() - 2 * mMirrorSurfaceMargin;
+ }
Rect tempRect = new Rect();
tempRect.set(mMagnificationFrame);
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java
index ae9775a0..9d573d3 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java
@@ -205,8 +205,9 @@
return;
}
- setAccessibilityServiceState(getContext(), serviceComponentName, /* enabled= */
- false);
+ setAccessibilityServiceState(
+ getContext(), serviceComponentName, /* enabled= */ false,
+ mSecureSettings.getRealUserHandle(UserHandle.USER_CURRENT));
});
}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/HistoryTracker.java b/packages/SystemUI/src/com/android/systemui/classifier/HistoryTracker.java
index 09bf04c..9cb26f3 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/HistoryTracker.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/HistoryTracker.java
@@ -20,9 +20,10 @@
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.util.time.SystemClock;
-import java.util.ArrayList;
+import com.google.common.collect.Sets;
+
import java.util.Collection;
-import java.util.List;
+import java.util.Set;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;
@@ -52,7 +53,7 @@
private final SystemClock mSystemClock;
DelayQueue<CombinedResult> mResults = new DelayQueue<>();
- private final List<BeliefListener> mBeliefListeners = new ArrayList<>();
+ private final Set<BeliefListener> mBeliefListeners = Sets.newConcurrentHashSet();
@Inject
HistoryTracker(SystemClock systemClock) {
@@ -161,11 +162,15 @@
}
void addBeliefListener(BeliefListener listener) {
- mBeliefListeners.add(listener);
+ if (listener != null) {
+ mBeliefListeners.add(listener);
+ }
}
void removeBeliefListener(BeliefListener listener) {
- mBeliefListeners.remove(listener);
+ if (listener != null) {
+ mBeliefListeners.remove(listener);
+ }
}
/**
* Represents a falsing score combing all the classifiers together.
diff --git a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalPrefsRepository.kt b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalPrefsRepository.kt
index b27fcfc..d8067b8 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalPrefsRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalPrefsRepository.kt
@@ -27,26 +27,17 @@
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.core.Logger
import com.android.systemui.log.dagger.CommunalLog
-import com.android.systemui.log.dagger.CommunalTableLog
-import com.android.systemui.log.table.TableLogBuffer
-import com.android.systemui.log.table.logDiffsForTable
import com.android.systemui.settings.UserFileManager
-import com.android.systemui.user.data.repository.UserRepository
import com.android.systemui.util.kotlin.SharedPreferencesExt.observe
import com.android.systemui.util.kotlin.emitOnStart
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
-import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.SharingStarted
-import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
-import kotlinx.coroutines.flow.onStart
-import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.withContext
/**
@@ -56,10 +47,16 @@
interface CommunalPrefsRepository {
/** Whether the CTA tile has been dismissed. */
- val isCtaDismissed: Flow<Boolean>
+ fun isCtaDismissed(user: UserInfo): Flow<Boolean>
+
+ /** Whether the lock screen widget disclaimer has been dismissed by the user. */
+ fun isDisclaimerDismissed(user: UserInfo): Flow<Boolean>
/** Save the CTA tile dismissed state for the current user. */
- suspend fun setCtaDismissedForCurrentUser()
+ suspend fun setCtaDismissed(user: UserInfo)
+
+ /** Save the lock screen widget disclaimer dismissed state for the current user. */
+ suspend fun setDisclaimerDismissed(user: UserInfo)
}
@OptIn(ExperimentalCoroutinesApi::class)
@@ -67,75 +64,43 @@
class CommunalPrefsRepositoryImpl
@Inject
constructor(
- @Background private val backgroundScope: CoroutineScope,
@Background private val bgDispatcher: CoroutineDispatcher,
- private val userRepository: UserRepository,
private val userFileManager: UserFileManager,
broadcastDispatcher: BroadcastDispatcher,
@CommunalLog logBuffer: LogBuffer,
- @CommunalTableLog tableLogBuffer: TableLogBuffer,
) : CommunalPrefsRepository {
+ private val logger by lazy { Logger(logBuffer, TAG) }
- private val logger = Logger(logBuffer, "CommunalPrefsRepositoryImpl")
+ override fun isCtaDismissed(user: UserInfo): Flow<Boolean> =
+ readKeyForUser(user, CTA_DISMISSED_STATE)
+
+ override fun isDisclaimerDismissed(user: UserInfo): Flow<Boolean> =
+ readKeyForUser(user, DISCLAIMER_DISMISSED_STATE)
/**
- * Emits an event each time a Backup & Restore restoration job is completed. Does not emit an
- * initial value.
+ * Emits an event each time a Backup & Restore restoration job is completed, and once at the
+ * start of collection.
*/
private val backupRestorationEvents: Flow<Unit> =
- broadcastDispatcher.broadcastFlow(
- filter = IntentFilter(BackupHelper.ACTION_RESTORE_FINISHED),
- flags = Context.RECEIVER_NOT_EXPORTED,
- permission = BackupHelper.PERMISSION_SELF,
- )
-
- override val isCtaDismissed: Flow<Boolean> =
- combine(
- userRepository.selectedUserInfo,
- // Make sure combine can emit even if we never get a Backup & Restore event,
- // which is the most common case as restoration only happens on initial device
- // setup.
- backupRestorationEvents.emitOnStart().onEach {
- logger.i("Restored state for communal preferences.")
- },
- ) { user, _ ->
- user
- }
- .flatMapLatest(::observeCtaDismissState)
- .logDiffsForTable(
- tableLogBuffer = tableLogBuffer,
- columnPrefix = "",
- columnName = "isCtaDismissed",
- initialValue = false,
+ broadcastDispatcher
+ .broadcastFlow(
+ filter = IntentFilter(BackupHelper.ACTION_RESTORE_FINISHED),
+ flags = Context.RECEIVER_NOT_EXPORTED,
+ permission = BackupHelper.PERMISSION_SELF,
)
- .stateIn(
- scope = backgroundScope,
- started = SharingStarted.WhileSubscribed(),
- initialValue = false,
- )
+ .onEach { logger.i("Restored state for communal preferences.") }
+ .emitOnStart()
- override suspend fun setCtaDismissedForCurrentUser() =
+ override suspend fun setCtaDismissed(user: UserInfo) =
withContext(bgDispatcher) {
- getSharedPrefsForUser(userRepository.getSelectedUserInfo())
- .edit()
- .putBoolean(CTA_DISMISSED_STATE, true)
- .apply()
-
+ getSharedPrefsForUser(user).edit().putBoolean(CTA_DISMISSED_STATE, true).apply()
logger.i("Dismissed CTA tile")
}
- private fun observeCtaDismissState(user: UserInfo): Flow<Boolean> =
- getSharedPrefsForUser(user)
- .observe()
- // Emit at the start of collection to ensure we get an initial value
- .onStart { emit(Unit) }
- .map { getCtaDismissedState() }
- .flowOn(bgDispatcher)
-
- private suspend fun getCtaDismissedState(): Boolean =
+ override suspend fun setDisclaimerDismissed(user: UserInfo) =
withContext(bgDispatcher) {
- getSharedPrefsForUser(userRepository.getSelectedUserInfo())
- .getBoolean(CTA_DISMISSED_STATE, false)
+ getSharedPrefsForUser(user).edit().putBoolean(DISCLAIMER_DISMISSED_STATE, true).apply()
+ logger.i("Dismissed widget disclaimer")
}
private fun getSharedPrefsForUser(user: UserInfo): SharedPreferences {
@@ -146,9 +111,19 @@
)
}
+ private fun readKeyForUser(user: UserInfo, key: String): Flow<Boolean> {
+ return backupRestorationEvents
+ .flatMapLatest {
+ val sharedPrefs = getSharedPrefsForUser(user)
+ sharedPrefs.observe().emitOnStart().map { sharedPrefs.getBoolean(key, false) }
+ }
+ .flowOn(bgDispatcher)
+ }
+
companion object {
- const val TAG = "CommunalRepository"
+ const val TAG = "CommunalPrefsRepository"
const val FILE_NAME = "communal_hub_prefs"
const val CTA_DISMISSED_STATE = "cta_dismissed"
+ const val DISCLAIMER_DISMISSED_STATE = "disclaimer_dismissed"
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
index 00678a8..9f3ade9 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
@@ -28,7 +28,6 @@
import com.android.compose.animation.scene.TransitionKey
import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.communal.data.repository.CommunalMediaRepository
-import com.android.systemui.communal.data.repository.CommunalPrefsRepository
import com.android.systemui.communal.data.repository.CommunalWidgetRepository
import com.android.systemui.communal.domain.model.CommunalContentModel
import com.android.systemui.communal.domain.model.CommunalContentModel.WidgetContent
@@ -99,7 +98,7 @@
@Background val bgDispatcher: CoroutineDispatcher,
broadcastDispatcher: BroadcastDispatcher,
private val widgetRepository: CommunalWidgetRepository,
- private val communalPrefsRepository: CommunalPrefsRepository,
+ private val communalPrefsInteractor: CommunalPrefsInteractor,
private val mediaRepository: CommunalMediaRepository,
smartspaceRepository: SmartspaceRepository,
keyguardInteractor: KeyguardInteractor,
@@ -325,7 +324,7 @@
}
/** Dismiss the CTA tile from the hub in view mode. */
- suspend fun dismissCtaTile() = communalPrefsRepository.setCtaDismissedForCurrentUser()
+ suspend fun dismissCtaTile() = communalPrefsInteractor.setCtaDismissed()
/** Add a widget at the specified position. */
fun addWidget(
@@ -461,7 +460,7 @@
/** CTA tile to be displayed in the glanceable hub (view mode). */
val ctaTileContent: Flow<List<CommunalContentModel.CtaTileInViewMode>> =
- communalPrefsRepository.isCtaDismissed.map { isDismissed ->
+ communalPrefsInteractor.isCtaDismissed.map { isDismissed ->
if (isDismissed) emptyList() else listOf(CommunalContentModel.CtaTileInViewMode())
}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalPrefsInteractor.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalPrefsInteractor.kt
new file mode 100644
index 0000000..3517650
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalPrefsInteractor.kt
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.communal.domain.interactor
+
+import android.content.pm.UserInfo
+import com.android.app.tracing.coroutines.launch
+import com.android.systemui.communal.data.repository.CommunalPrefsRepository
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.log.dagger.CommunalTableLog
+import com.android.systemui.log.table.TableLogBuffer
+import com.android.systemui.log.table.logDiffsForTable
+import com.android.systemui.settings.UserTracker
+import com.android.systemui.user.domain.interactor.SelectedUserInteractor
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.stateIn
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SysUISingleton
+class CommunalPrefsInteractor
+@Inject
+constructor(
+ @Background private val bgScope: CoroutineScope,
+ private val repository: CommunalPrefsRepository,
+ userInteractor: SelectedUserInteractor,
+ private val userTracker: UserTracker,
+ @CommunalTableLog tableLogBuffer: TableLogBuffer
+) {
+
+ val isCtaDismissed: Flow<Boolean> =
+ userInteractor.selectedUserInfo
+ .flatMapLatest { user -> repository.isCtaDismissed(user) }
+ .logDiffsForTable(
+ tableLogBuffer = tableLogBuffer,
+ columnPrefix = "",
+ columnName = "isCtaDismissed",
+ initialValue = false,
+ )
+ .stateIn(
+ scope = bgScope,
+ started = SharingStarted.WhileSubscribed(),
+ initialValue = false,
+ )
+
+ suspend fun setCtaDismissed(user: UserInfo = userTracker.userInfo) =
+ repository.setCtaDismissed(user)
+
+ val isDisclaimerDismissed: Flow<Boolean> =
+ userInteractor.selectedUserInfo
+ .flatMapLatest { user -> repository.isDisclaimerDismissed(user) }
+ .logDiffsForTable(
+ tableLogBuffer = tableLogBuffer,
+ columnPrefix = "",
+ columnName = "isDisclaimerDismissed",
+ initialValue = false,
+ )
+ .stateIn(
+ scope = bgScope,
+ started = SharingStarted.WhileSubscribed(),
+ initialValue = false,
+ )
+
+ fun setDisclaimerDismissed(user: UserInfo = userTracker.userInfo) {
+ bgScope.launch("$TAG#setDisclaimerDismissed") { repository.setDisclaimerDismissed(user) }
+ }
+
+ private companion object {
+ const val TAG = "CommunalPrefsInteractor"
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt
index c0c5861..9185384 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt
@@ -26,6 +26,7 @@
import com.android.internal.logging.UiEventLogger
import com.android.systemui.Flags.enableWidgetPickerSizeFilter
import com.android.systemui.communal.domain.interactor.CommunalInteractor
+import com.android.systemui.communal.domain.interactor.CommunalPrefsInteractor
import com.android.systemui.communal.domain.interactor.CommunalSceneInteractor
import com.android.systemui.communal.domain.interactor.CommunalSettingsInteractor
import com.android.systemui.communal.domain.model.CommunalContentModel
@@ -42,6 +43,7 @@
import com.android.systemui.media.dagger.MediaModule
import com.android.systemui.res.R
import com.android.systemui.util.kotlin.BooleanFlowOperators.allOf
+import com.android.systemui.util.kotlin.BooleanFlowOperators.not
import javax.inject.Inject
import javax.inject.Named
import kotlinx.coroutines.CoroutineDispatcher
@@ -67,6 +69,7 @@
private val uiEventLogger: UiEventLogger,
@CommunalLog logBuffer: LogBuffer,
@Background private val backgroundDispatcher: CoroutineDispatcher,
+ private val communalPrefsInteractor: CommunalPrefsInteractor,
) : BaseCommunalViewModel(communalSceneInteractor, communalInteractor, mediaHost) {
private val logger = Logger(logBuffer, "CommunalEditModeViewModel")
@@ -76,9 +79,16 @@
override val isCommunalContentVisible: Flow<Boolean> =
communalSceneInteractor.editModeState.map { it == EditModeState.SHOWING }
+ val showDisclaimer: Flow<Boolean> =
+ allOf(isCommunalContentVisible, not(communalPrefsInteractor.isDisclaimerDismissed))
+
+ fun onDisclaimerDismissed() {
+ communalPrefsInteractor.setDisclaimerDismissed()
+ }
+
/**
- * Emits when edit mode activity can show, after we've transitioned to [KeyguardState.GONE]
- * and edit mode is open.
+ * Emits when edit mode activity can show, after we've transitioned to [KeyguardState.GONE] and
+ * edit mode is open.
*/
val canShowEditMode =
allOf(
diff --git a/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt b/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt
index d4a166f..0bcfa96 100644
--- a/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt
@@ -178,7 +178,15 @@
.mapElementsLazily { displayId -> getDisplay(displayId) }
.flowOn(backgroundCoroutineDispatcher)
.debugLog("enabledDisplays")
- .stateIn(bgApplicationScope, SharingStarted.WhileSubscribed(), emptySet())
+ .stateIn(
+ bgApplicationScope,
+ started = SharingStarted.WhileSubscribed(),
+ initialValue =
+ setOf(
+ getDisplay(Display.DEFAULT_DISPLAY)
+ ?: error("Unable to get default display.")
+ )
+ )
} else {
oldEnabledDisplays
}
diff --git a/packages/SystemUI/src/com/android/systemui/display/domain/interactor/ConnectedDisplayInteractor.kt b/packages/SystemUI/src/com/android/systemui/display/domain/interactor/ConnectedDisplayInteractor.kt
index 73b7a8a..e4b290d 100644
--- a/packages/SystemUI/src/com/android/systemui/display/domain/interactor/ConnectedDisplayInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/display/domain/interactor/ConnectedDisplayInteractor.kt
@@ -85,7 +85,7 @@
class ConnectedDisplayInteractorImpl
@Inject
constructor(
- private val virtualDeviceManager: VirtualDeviceManager,
+ private val virtualDeviceManager: VirtualDeviceManager?,
keyguardRepository: KeyguardRepository,
displayRepository: DisplayRepository,
deviceStateRepository: DeviceStateRepository,
@@ -156,6 +156,7 @@
private fun isVirtualDeviceOwnedMirrorDisplay(display: Display): Boolean {
return Flags.interactiveScreenMirror() &&
+ virtualDeviceManager != null &&
virtualDeviceManager.isVirtualDeviceOwnedMirrorDisplay(display.displayId)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/source/MultitaskingShortcutsSource.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/source/MultitaskingShortcutsSource.kt
new file mode 100644
index 0000000..34b10c7
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/source/MultitaskingShortcutsSource.kt
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyboard.shortcut.data.source
+
+import android.content.res.Resources
+import android.view.KeyEvent.KEYCODE_DPAD_LEFT
+import android.view.KeyEvent.KEYCODE_DPAD_RIGHT
+import android.view.KeyEvent.KEYCODE_DPAD_UP
+import android.view.KeyEvent.KEYCODE_TAB
+import android.view.KeyEvent.META_ALT_ON
+import android.view.KeyEvent.META_CTRL_ON
+import android.view.KeyEvent.META_META_ON
+import android.view.KeyEvent.META_SHIFT_ON
+import com.android.systemui.keyboard.shortcut.shared.model.shortcut
+import com.android.systemui.res.R
+import javax.inject.Inject
+
+class MultitaskingShortcutsSource @Inject constructor(private val resources: Resources) {
+
+ fun splitScreenShortcuts() =
+ listOf(
+ // Enter Split screen with current app to RHS:
+ // - Meta + Ctrl + Right arrow
+ shortcut(resources.getString(R.string.system_multitasking_rhs)) {
+ command(META_META_ON, META_CTRL_ON, KEYCODE_DPAD_RIGHT)
+ },
+ // Enter Split screen with current app to LHS:
+ // - Meta + Ctrl + Left arrow
+ shortcut(resources.getString(R.string.system_multitasking_lhs)) {
+ command(META_META_ON, META_CTRL_ON, KEYCODE_DPAD_LEFT)
+ },
+ // Switch from Split screen to full screen:
+ // - Meta + Ctrl + Up arrow
+ shortcut(resources.getString(R.string.system_multitasking_full_screen)) {
+ command(META_META_ON, META_CTRL_ON, KEYCODE_DPAD_UP)
+ },
+ // Change split screen focus to RHS:
+ // - Meta + Alt + Right arrow
+ shortcut(resources.getString(R.string.system_multitasking_splitscreen_focus_rhs)) {
+ command(META_META_ON, META_ALT_ON, KEYCODE_DPAD_RIGHT)
+ },
+ // Change split screen focus to LHS:
+ // - Meta + Alt + Left arrow
+ shortcut(resources.getString(R.string.system_multitasking_splitscreen_focus_rhs)) {
+ command(META_META_ON, META_ALT_ON, KEYCODE_DPAD_LEFT)
+ },
+ )
+
+ fun recentsShortcuts() =
+ listOf(
+ // Cycle through recent apps (forward):
+ // - Alt + Tab
+ shortcut(resources.getString(R.string.group_system_cycle_forward)) {
+ command(META_ALT_ON, KEYCODE_TAB)
+ },
+ // Cycle through recent apps (back):
+ // - Shift + Alt + Tab
+ shortcut(resources.getString(R.string.group_system_cycle_back)) {
+ command(META_SHIFT_ON, META_ALT_ON, KEYCODE_TAB)
+ },
+ )
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/source/SystemShortcutsSource.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/source/SystemShortcutsSource.kt
new file mode 100644
index 0000000..a4304e5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/source/SystemShortcutsSource.kt
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyboard.shortcut.data.source
+
+import android.content.res.Resources
+import android.view.KeyEvent.KEYCODE_A
+import android.view.KeyEvent.KEYCODE_DEL
+import android.view.KeyEvent.KEYCODE_DPAD_LEFT
+import android.view.KeyEvent.KEYCODE_ENTER
+import android.view.KeyEvent.KEYCODE_ESCAPE
+import android.view.KeyEvent.KEYCODE_H
+import android.view.KeyEvent.KEYCODE_I
+import android.view.KeyEvent.KEYCODE_L
+import android.view.KeyEvent.KEYCODE_N
+import android.view.KeyEvent.KEYCODE_S
+import android.view.KeyEvent.KEYCODE_SLASH
+import android.view.KeyEvent.KEYCODE_TAB
+import android.view.KeyEvent.META_CTRL_ON
+import android.view.KeyEvent.META_META_ON
+import com.android.systemui.keyboard.shortcut.shared.model.shortcut
+import com.android.systemui.res.R
+import javax.inject.Inject
+
+class SystemShortcutsSource @Inject constructor(private val resources: Resources) {
+
+ fun generalShortcuts() =
+ listOf(
+ // Access list of all apps and search (i.e. Search/Launcher):
+ // - Meta
+ shortcut(resources.getString(R.string.group_system_access_all_apps_search)) {
+ command(META_META_ON)
+ },
+ // Access home screen:
+ // - Meta + H
+ // - Meta + Enter
+ shortcut(resources.getString(R.string.group_system_access_home_screen)) {
+ command(META_META_ON, KEYCODE_H)
+ command(META_META_ON, KEYCODE_ENTER)
+ },
+ // Overview of open apps:
+ // - Meta + Tab
+ shortcut(resources.getString(R.string.group_system_overview_open_apps)) {
+ command(META_META_ON, KEYCODE_TAB)
+ },
+ // Back: go back to previous state (back button)
+ // - Meta + Escape OR
+ // - Meta + Backspace OR
+ // - Meta + Left arrow
+ shortcut(resources.getString(R.string.group_system_go_back)) {
+ command(META_META_ON, KEYCODE_ESCAPE)
+ command(META_META_ON, KEYCODE_DEL)
+ command(META_META_ON, KEYCODE_DPAD_LEFT)
+ },
+ // Take a full screenshot:
+ // - Meta + Ctrl + S
+ shortcut(resources.getString(R.string.group_system_full_screenshot)) {
+ command(META_META_ON, META_CTRL_ON, KEYCODE_S)
+ },
+ // Access list of system / apps shortcuts:
+ // - Meta + /
+ shortcut(resources.getString(R.string.group_system_access_system_app_shortcuts)) {
+ command(META_META_ON, KEYCODE_SLASH)
+ },
+ // Access notification shade:
+ // - Meta + N
+ shortcut(resources.getString(R.string.group_system_access_notification_shade)) {
+ command(META_META_ON, KEYCODE_N)
+ },
+ // Lock screen:
+ // - Meta + L
+ shortcut(resources.getString(R.string.group_system_lock_screen)) {
+ command(META_META_ON, KEYCODE_L)
+ },
+ )
+
+ fun systemAppsShortcuts() =
+ listOf(
+ // Pull up Notes app for quick memo:
+ // - Meta + Ctrl + N
+ shortcut(resources.getString(R.string.group_system_quick_memo)) {
+ command(META_META_ON, META_CTRL_ON, KEYCODE_N)
+ },
+ // Access system settings:
+ // - Meta + I
+ shortcut(resources.getString(R.string.group_system_access_system_settings)) {
+ command(META_META_ON, KEYCODE_I)
+ },
+ // Access Assistant:
+ // - Meta + A
+ shortcut(resources.getString(R.string.group_system_access_google_assistant)) {
+ command(META_META_ON, KEYCODE_A)
+ },
+ )
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/Shortcut.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/Shortcut.kt
new file mode 100644
index 0000000..ea90b18
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/Shortcut.kt
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyboard.shortcut.shared.model
+
+import android.graphics.drawable.Icon
+
+data class Shortcut(val label: String, val icon: Icon? = null, val commands: List<ShortcutCommand>)
+
+class ShortcutBuilder(private val label: String, private val icon: Icon? = null) {
+ val commands = mutableListOf<ShortcutCommand>()
+
+ fun command(vararg keyCodes: Int) {
+ commands += ShortcutCommand(keyCodes.toList())
+ }
+
+ fun build() = Shortcut(label, icon, commands)
+}
+
+fun shortcut(label: String, icon: Icon? = null, block: ShortcutBuilder.() -> Unit): Shortcut =
+ ShortcutBuilder(label).apply(block).build()
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutCommand.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutCommand.kt
new file mode 100644
index 0000000..747efba
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutCommand.kt
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyboard.shortcut.shared.model
+
+class ShortcutCommand(val keyCodes: List<Int>)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt
index 49d00af..5573f0d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt
@@ -40,6 +40,7 @@
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.drop
import kotlinx.coroutines.flow.emptyFlow
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.flatMapLatest
@@ -168,7 +169,9 @@
keyguardInteractor.isKeyguardGoingAway.filter { it }.map {}, // map to Unit
keyguardInteractor.isKeyguardOccluded.flatMapLatest { keyguardOccluded ->
if (keyguardOccluded) {
- primaryBouncerInteractor.keyguardAuthenticatedBiometricsHandled
+ primaryBouncerInteractor.keyguardAuthenticatedBiometricsHandled.drop(
+ 1
+ ) // drop the initial state
} else {
emptyFlow()
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerViewBinder.kt
index f8063c9..db33acb 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerViewBinder.kt
@@ -115,13 +115,28 @@
}
private fun removeViewFromWindowManager() {
- if (alternateBouncerView == null || !alternateBouncerView!!.isAttachedToWindow) {
- return
- }
+ alternateBouncerView?.let {
+ alternateBouncerView = null
+ if (it.isAttachedToWindow) {
+ it.removeOnAttachStateChangeListener(onAttachAddBackGestureHandler)
+ Log.d(TAG, "Removing alternate bouncer view immediately")
+ windowManager.get().removeView(it)
+ } else {
+ // once the view is attached, remove it
+ it.addOnAttachStateChangeListener(
+ object : View.OnAttachStateChangeListener {
+ override fun onViewAttachedToWindow(view: View) {
+ it.removeOnAttachStateChangeListener(this)
+ it.removeOnAttachStateChangeListener(onAttachAddBackGestureHandler)
+ Log.d(TAG, "Removing alternate bouncer view on attached")
+ windowManager.get().removeView(it)
+ }
- windowManager.get().removeView(alternateBouncerView)
- alternateBouncerView!!.removeOnAttachStateChangeListener(onAttachAddBackGestureHandler)
- alternateBouncerView = null
+ override fun onViewDetachedFromWindow(view: View) {}
+ }
+ )
+ }
+ }
}
private val onAttachAddBackGestureHandler =
@@ -151,7 +166,7 @@
}
private fun addViewToWindowManager() {
- if (alternateBouncerView?.isAttachedToWindow == true) {
+ if (alternateBouncerView != null) {
return
}
@@ -159,6 +174,7 @@
layoutInflater.get().inflate(R.layout.alternate_bouncer, null, false)
as ConstraintLayout
+ Log.d(TAG, "Adding alternate bouncer view")
windowManager.get().addView(alternateBouncerView, layoutParams)
alternateBouncerView!!.addOnAttachStateChangeListener(onAttachAddBackGestureHandler)
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardIndicationAreaBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardIndicationAreaBinder.kt
index 23c2491..3e4253b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardIndicationAreaBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardIndicationAreaBinder.kt
@@ -29,6 +29,7 @@
import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.res.R
import com.android.systemui.statusbar.KeyguardIndicationController
+import com.android.systemui.util.kotlin.DisposableHandles
import kotlinx.coroutines.DisposableHandle
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
@@ -53,7 +54,15 @@
viewModel: KeyguardIndicationAreaViewModel,
indicationController: KeyguardIndicationController,
): DisposableHandle {
- indicationController.setIndicationArea(view)
+ val disposables = DisposableHandles()
+
+ // As the indication controller is a singleton, reset the view back to the previous view
+ // once the current view is disposed.
+ val previous = indicationController.indicationArea
+ indicationController.indicationArea = view
+ disposables += DisposableHandle {
+ previous?.let { indicationController.indicationArea = it }
+ }
val indicationText: TextView = view.requireViewById(R.id.keyguard_indication_text)
val indicationTextBottom: TextView =
@@ -63,7 +72,7 @@
view.clipToPadding = false
val configurationBasedDimensions = MutableStateFlow(loadFromResources(view))
- val disposableHandle =
+ disposables +=
view.repeatWhenAttached {
repeatOnLifecycle(Lifecycle.State.STARTED) {
launch("$TAG#viewModel.alpha") {
@@ -126,7 +135,7 @@
}
}
}
- return disposableHandle
+ return disposables
}
private fun loadFromResources(view: View): ConfigurationBasedDimensions {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModel.kt
index 4688088..5ce1b5e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModel.kt
@@ -284,9 +284,9 @@
private fun DeviceEntryIconView.IconType.toAccessibilityHintType():
DeviceEntryIconView.AccessibilityHintType {
return when (this) {
+ DeviceEntryIconView.IconType.FINGERPRINT,
DeviceEntryIconView.IconType.LOCK -> DeviceEntryIconView.AccessibilityHintType.BOUNCER
DeviceEntryIconView.IconType.UNLOCK -> DeviceEntryIconView.AccessibilityHintType.ENTER
- DeviceEntryIconView.IconType.FINGERPRINT,
DeviceEntryIconView.IconType.NONE -> DeviceEntryIconView.AccessibilityHintType.NONE
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/data/repository/MediaFilterRepository.kt b/packages/SystemUI/src/com/android/systemui/media/controls/data/repository/MediaFilterRepository.kt
index 6a91d1b..a2d7fb1 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/data/repository/MediaFilterRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/data/repository/MediaFilterRepository.kt
@@ -26,6 +26,8 @@
import com.android.systemui.media.controls.shared.model.MediaDataLoadingModel
import com.android.systemui.media.controls.shared.model.SmartspaceMediaData
import com.android.systemui.media.controls.shared.model.SmartspaceMediaLoadingModel
+import com.android.systemui.media.controls.util.MediaSmartspaceLogger
+import com.android.systemui.media.controls.util.SmallHash
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.util.time.SystemClock
import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow
@@ -43,9 +45,10 @@
class MediaFilterRepository
@Inject
constructor(
- @Application applicationContext: Context,
+ @Application private val applicationContext: Context,
private val systemClock: SystemClock,
private val configurationController: ConfigurationController,
+ private val smartspaceLogger: MediaSmartspaceLogger,
) {
val onAnyMediaConfigurationChange: Flow<Unit> = conflatedCallbackFlow {
@@ -211,6 +214,12 @@
isMediaFromRec(it)
)
sortedMap[sortKey] = newCommonModel
+ val isUpdate =
+ sortedMedia.values.any { commonModel ->
+ commonModel is MediaCommonModel.MediaControl &&
+ commonModel.mediaLoadedModel.instanceId ==
+ mediaDataLoadingModel.instanceId
+ }
// On Addition or tapping on recommendations, we should show the new order of media.
if (mediaFromRecPackageName == it.packageName) {
@@ -218,30 +227,50 @@
mediaFromRecPackageName = null
_currentMedia.value = sortedMap.values.toList()
}
- } else if (sortedMap.size > _currentMedia.value.size && it.active) {
- _currentMedia.value = sortedMap.values.toList()
} else {
- // When loading an update for an existing media control.
+ var isNewToCurrentMedia = true
val currentList =
mutableListOf<MediaCommonModel>().apply { addAll(_currentMedia.value) }
currentList.forEachIndexed { index, mediaCommonModel ->
if (
mediaCommonModel is MediaCommonModel.MediaControl &&
mediaCommonModel.mediaLoadedModel.instanceId ==
- mediaDataLoadingModel.instanceId &&
- mediaCommonModel != newCommonModel
+ mediaDataLoadingModel.instanceId
) {
- // Update media model if changed.
- currentList[index] = newCommonModel
+ // When loading an update for an existing media control.
+ isNewToCurrentMedia = false
+ if (mediaCommonModel != newCommonModel) {
+ // Update media model if changed.
+ currentList[index] = newCommonModel
+ }
}
}
- _currentMedia.value = currentList
+ if (isNewToCurrentMedia && it.active) {
+ _currentMedia.value = sortedMap.values.toList()
+ } else {
+ _currentMedia.value = currentList
+ }
+ }
+
+ sortedMedia = sortedMap
+
+ if (!isUpdate) {
+ val rank = sortedMedia.values.indexOf(newCommonModel)
+ if (isSmartspaceLoggingEnabled(newCommonModel, rank)) {
+ smartspaceLogger.logSmartspaceCardReceived(
+ it.smartspaceId,
+ it.appUid,
+ cardinality = _currentMedia.value.size,
+ isSsReactivated = mediaDataLoadingModel.isSsReactivated,
+ rank = rank,
+ )
+ }
+ } else if (mediaDataLoadingModel.receivedSmartspaceCardLatency != 0) {
+ logSmartspaceAllMediaCards(mediaDataLoadingModel.receivedSmartspaceCardLatency)
}
}
}
- sortedMedia = sortedMap
-
// On removal we want to keep the order being shown to user.
if (mediaDataLoadingModel is MediaDataLoadingModel.Removed) {
_currentMedia.value =
@@ -249,6 +278,7 @@
commonModel !is MediaCommonModel.MediaControl ||
mediaDataLoadingModel.instanceId != commonModel.mediaLoadedModel.instanceId
}
+ sortedMedia = sortedMap
}
}
@@ -271,21 +301,45 @@
isPlaying = false,
active = _smartspaceMediaData.value.isActive,
)
+ val newCommonModel = MediaCommonModel.MediaRecommendations(smartspaceMediaLoadingModel)
when (smartspaceMediaLoadingModel) {
- is SmartspaceMediaLoadingModel.Loaded ->
- sortedMap[sortKey] =
- MediaCommonModel.MediaRecommendations(smartspaceMediaLoadingModel)
- is SmartspaceMediaLoadingModel.Removed ->
+ is SmartspaceMediaLoadingModel.Loaded -> {
+ sortedMap[sortKey] = newCommonModel
+ _currentMedia.value = sortedMap.values.toList()
+ sortedMedia = sortedMap
+
+ if (isRecommendationActive()) {
+ val hasActivatedExistedResumeMedia =
+ !hasActiveMedia() &&
+ hasAnyMedia() &&
+ smartspaceMediaLoadingModel.isPrioritized
+ if (hasActivatedExistedResumeMedia) {
+ // Log resume card received if resumable media card is reactivated and
+ // recommendation card is valid and ranked first
+ logSmartspaceAllMediaCards(
+ (systemClock.currentTimeMillis() -
+ _smartspaceMediaData.value.headphoneConnectionTimeMillis)
+ .toInt()
+ )
+ }
+
+ smartspaceLogger.logSmartspaceCardReceived(
+ SmallHash.hash(_smartspaceMediaData.value.targetId),
+ _smartspaceMediaData.value.getUid(applicationContext),
+ cardinality = _currentMedia.value.size,
+ isRecommendationCard = true,
+ rank = _currentMedia.value.indexOf(newCommonModel),
+ )
+ }
+ }
+ is SmartspaceMediaLoadingModel.Removed -> {
_currentMedia.value =
_currentMedia.value.filter { commonModel ->
commonModel !is MediaCommonModel.MediaRecommendations
}
+ sortedMedia = sortedMap
+ }
}
-
- if (sortedMap.size > sortedMedia.size) {
- _currentMedia.value = sortedMap.values.toList()
- }
- sortedMedia = sortedMap
}
fun setOrderedMedia() {
@@ -315,4 +369,35 @@
private fun isMediaFromRec(data: MediaData): Boolean {
return data.isPlaying == true && mediaFromRecPackageName == data.packageName
}
+
+ /** Log all media cards if smartspace logging is enabled for each. */
+ private fun logSmartspaceAllMediaCards(receivedSmartspaceCardLatency: Int) {
+ sortedMedia.values.forEachIndexed { index, mediaCommonModel ->
+ if (mediaCommonModel is MediaCommonModel.MediaControl) {
+ _selectedUserEntries.value[mediaCommonModel.mediaLoadedModel.instanceId]?.let {
+ it.smartspaceId =
+ SmallHash.hash(it.appUid + systemClock.currentTimeMillis().toInt())
+ it.isImpressed = false
+
+ if (isSmartspaceLoggingEnabled(mediaCommonModel, index)) {
+ smartspaceLogger.logSmartspaceCardReceived(
+ it.smartspaceId,
+ it.appUid,
+ cardinality = _currentMedia.value.size,
+ isSsReactivated = mediaCommonModel.mediaLoadedModel.isSsReactivated,
+ rank = index,
+ receivedLatencyMillis = receivedSmartspaceCardLatency,
+ )
+ }
+ }
+ }
+ }
+ }
+
+ private fun isSmartspaceLoggingEnabled(commonModel: MediaCommonModel, index: Int): Boolean {
+ return sortedMedia.size > index &&
+ (_smartspaceMediaData.value.expiryTimeMs != 0L ||
+ isRecommendationActive() ||
+ commonModel is MediaCommonModel.MediaRecommendations)
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataFilterImpl.kt b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataFilterImpl.kt
index f78a0f9..31bd4fb 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataFilterImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataFilterImpl.kt
@@ -180,7 +180,13 @@
mediaData.instanceId
)
mediaFilterRepository.addMediaDataLoadingState(
- MediaDataLoadingModel.Loaded(lastActiveId)
+ MediaDataLoadingModel.Loaded(
+ lastActiveId,
+ receivedSmartspaceCardLatency =
+ (systemClock.currentTimeMillis() - data.headphoneConnectionTimeMillis)
+ .toInt(),
+ isSsReactivated = true
+ )
)
mediaLoadingLogger.logMediaLoaded(
mediaData.instanceId,
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataProcessor.kt b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataProcessor.kt
index 37dffd1..adcfba7 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataProcessor.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataProcessor.kt
@@ -86,6 +86,7 @@
import com.android.systemui.media.controls.util.MediaDataUtils
import com.android.systemui.media.controls.util.MediaFlags
import com.android.systemui.media.controls.util.MediaUiEventLogger
+import com.android.systemui.media.controls.util.SmallHash
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.plugins.BcSmartspaceDataPlugin
import com.android.systemui.res.R
@@ -721,6 +722,7 @@
appUid = appUid,
isExplicit = isExplicit,
resumeProgress = progress,
+ smartspaceId = SmallHash.hash(appUid + systemClock.currentTimeMillis().toInt()),
)
)
}
@@ -902,6 +904,7 @@
instanceId = instanceId,
appUid = appUid,
isExplicit = isExplicit,
+ smartspaceId = SmallHash.hash(appUid + systemClock.currentTimeMillis().toInt()),
)
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/shared/model/MediaData.kt b/packages/SystemUI/src/com/android/systemui/media/controls/shared/model/MediaData.kt
index 11a5629..40b3477 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/shared/model/MediaData.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/shared/model/MediaData.kt
@@ -99,6 +99,12 @@
/** Track progress (0 - 1) to display for players where [resumption] is true */
val resumeProgress: Double? = null,
+
+ /** Smartspace Id, used for logging. */
+ var smartspaceId: Int = -1,
+
+ /** If media card was visible to user, used for logging. */
+ var isImpressed: Boolean = false,
) {
companion object {
/** Media is playing on the local device */
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/shared/model/MediaDataLoadingModel.kt b/packages/SystemUI/src/com/android/systemui/media/controls/shared/model/MediaDataLoadingModel.kt
index 170f1f7..c8a02fa 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/shared/model/MediaDataLoadingModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/shared/model/MediaDataLoadingModel.kt
@@ -27,6 +27,8 @@
data class Loaded(
override val instanceId: InstanceId,
val immediatelyUpdateUi: Boolean = true,
+ val receivedSmartspaceCardLatency: Int = 0,
+ val isSsReactivated: Boolean = false,
) : MediaDataLoadingModel()
/** Media data has been removed. */
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/shared/model/SmartspaceMediaData.kt b/packages/SystemUI/src/com/android/systemui/media/controls/shared/model/SmartspaceMediaData.kt
index 9e15dbb..96c3fa8 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/shared/model/SmartspaceMediaData.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/shared/model/SmartspaceMediaData.kt
@@ -48,6 +48,8 @@
val instanceId: InstanceId? = null,
/** The timestamp in milliseconds indicating when the card should be removed */
val expiryTimeMs: Long = 0L,
+ /** If recommendation card was visible to user, used for logging. */
+ var isImpressed: Boolean = false,
) {
/**
* Indicates if all the data is valid.
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaSmartspaceLogger.kt b/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaSmartspaceLogger.kt
new file mode 100644
index 0000000..01fbf4a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaSmartspaceLogger.kt
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.media.controls.util
+
+import android.util.Log
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.shared.system.SysUiStatsLog
+import javax.inject.Inject
+
+/** Logger class for Smartspace logging events. */
+@SysUISingleton
+class MediaSmartspaceLogger @Inject constructor() {
+ /**
+ * Log Smartspace card received event
+ *
+ * @param instanceId id to uniquely identify a card.
+ * @param uid uid for the application that media comes from.
+ * @param cardinality number of card in carousel.
+ * @param isRecommendationCard whether media card being logged is a recommendations card.
+ * @param isSsReactivated indicates resume media card is reactivated by Smartspace
+ * recommendation signal
+ * @param rank the rank for media card in the media carousel, starting from 0
+ * @param receivedLatencyMillis latency in milliseconds for card received events.
+ */
+ fun logSmartspaceCardReceived(
+ instanceId: Int,
+ uid: Int,
+ cardinality: Int,
+ isRecommendationCard: Boolean = false,
+ isSsReactivated: Boolean = false,
+ rank: Int = 0,
+ receivedLatencyMillis: Int = 0,
+ ) {
+ logSmartspaceCardReported(
+ SMARTSPACE_CARD_RECEIVED_EVENT,
+ instanceId,
+ uid,
+ surfaces =
+ intArrayOf(
+ SysUiStatsLog.SMART_SPACE_CARD_REPORTED__DISPLAY_SURFACE__SHADE,
+ SysUiStatsLog.SMART_SPACE_CARD_REPORTED__DISPLAY_SURFACE__LOCKSCREEN,
+ SysUiStatsLog.SMART_SPACE_CARD_REPORTED__DISPLAY_SURFACE__DREAM_OVERLAY,
+ ),
+ cardinality,
+ isRecommendationCard,
+ isSsReactivated,
+ rank = rank,
+ receivedLatencyMillis = receivedLatencyMillis,
+ )
+ }
+
+ /**
+ * Log Smartspace card UI event
+ *
+ * @param eventId id of the event. eg: dismiss, click, or seen.
+ * @param instanceId id to uniquely identify a card.
+ * @param uid uid for the application that media comes from.
+ * @param location location of media carousel holding media card.
+ * @param cardinality number of card in carousel.
+ * @param isRecommendationCard whether media card being logged is a recommendations card.
+ * @param isSsReactivated indicates resume media card is reactivated by Smartspace
+ * recommendation signal
+ * @param rank the rank for media card in the media carousel, starting from 0
+ * @param isSwipeToDismiss whether is to log swipe-to-dismiss event
+ */
+ fun logSmartspaceCardUIEvent(
+ eventId: Int,
+ instanceId: Int,
+ uid: Int,
+ location: Int,
+ cardinality: Int,
+ isRecommendationCard: Boolean = false,
+ isSsReactivated: Boolean = false,
+ rank: Int = 0,
+ isSwipeToDismiss: Boolean = false,
+ ) {
+ logSmartspaceCardReported(
+ eventId,
+ instanceId,
+ uid,
+ surfaces = intArrayOf(location),
+ cardinality,
+ isRecommendationCard,
+ isSsReactivated,
+ rank = rank,
+ isSwipeToDismiss = isSwipeToDismiss,
+ )
+ }
+
+ /**
+ * Log Smartspace events
+ *
+ * @param eventId UI event id (e.g. 800 for SMARTSPACE_CARD_SEEN)
+ * @param instanceId id to uniquely identify a card, e.g. each headphone generates a new
+ * instanceId
+ * @param uid uid for the application that media comes from
+ * @param surfaces list of display surfaces the media card is on (e.g. lockscreen, shade) when
+ * the event happened
+ * @param cardinality number of card in carousel.
+ * @param isRecommendationCard whether media card being logged is a recommendations card.
+ * @param isSsReactivated indicates resume media card is reactivated by Smartspace
+ * recommendation signal
+ * @param interactedSubcardRank the rank for interacted media item for recommendation card, -1
+ * for tapping on card but not on any media item, 0 for first media item, 1 for second, etc.
+ * @param interactedSubcardCardinality how many media items were shown to the user when there is
+ * user interaction
+ * @param rank the rank for media card in the media carousel, starting from 0
+ * @param receivedLatencyMillis latency in milliseconds for card received events. E.g. latency
+ * between headphone connection to sysUI displays media recommendation card
+ * @param isSwipeToDismiss whether is to log swipe-to-dismiss event
+ */
+ private fun logSmartspaceCardReported(
+ eventId: Int,
+ instanceId: Int,
+ uid: Int,
+ surfaces: IntArray,
+ cardinality: Int,
+ isRecommendationCard: Boolean,
+ isSsReactivated: Boolean,
+ interactedSubcardRank: Int = 0,
+ interactedSubcardCardinality: Int = 0,
+ rank: Int = 0,
+ receivedLatencyMillis: Int = 0,
+ isSwipeToDismiss: Boolean = false,
+ ) {
+ surfaces.forEach { surface ->
+ SysUiStatsLog.write(
+ SysUiStatsLog.SMARTSPACE_CARD_REPORTED,
+ eventId,
+ instanceId,
+ // Deprecated, replaced with AiAi feature type so we don't need to create logging
+ // card type for each new feature.
+ SysUiStatsLog.SMART_SPACE_CARD_REPORTED__CARD_TYPE__UNKNOWN_CARD,
+ surface,
+ // Use -1 as rank value to indicate user swipe to dismiss the card
+ if (isSwipeToDismiss) -1 else rank,
+ cardinality,
+ if (isRecommendationCard) {
+ 15 // MEDIA_RECOMMENDATION
+ } else if (isSsReactivated) {
+ 43 // MEDIA_RESUME_SS_ACTIVATED
+ } else {
+ 31 // MEDIA_RESUME
+ },
+ uid,
+ interactedSubcardRank,
+ interactedSubcardCardinality,
+ receivedLatencyMillis,
+ null, // Media cards cannot have subcards.
+ null // Media cards don't have dimensions today.
+ )
+
+ if (DEBUG) {
+ Log.d(
+ TAG,
+ "Log Smartspace card event id: $eventId instance id: $instanceId" +
+ " surface: $surface rank: $rank cardinality: $cardinality " +
+ "isRecommendationCard: $isRecommendationCard " +
+ "isSsReactivated: $isSsReactivated" +
+ "uid: $uid " +
+ "interactedSubcardRank: $interactedSubcardRank " +
+ "interactedSubcardCardinality: $interactedSubcardCardinality " +
+ "received_latency_millis: $receivedLatencyMillis"
+ )
+ }
+ }
+ }
+
+ companion object {
+ private const val TAG = "MediaSmartspaceLogger"
+ private val DEBUG = Log.isLoggable(TAG, Log.DEBUG)
+ private const val SMARTSPACE_CARD_RECEIVED_EVENT = 759
+ const val SMARTSPACE_CARD_CLICK_EVENT = 760
+ const val SMARTSPACE_CARD_DISMISS_EVENT = 761
+ const val SMARTSPACE_CARD_SEEN_EVENT = 800
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
index 1e86563..b48b409 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
@@ -85,6 +85,7 @@
import com.android.systemui.animation.DialogTransitionAnimator;
import com.android.systemui.broadcast.BroadcastSender;
import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.media.dialog.MediaItem.MediaItemType;
import com.android.systemui.media.nearby.NearbyMediaDevicesManager;
import com.android.systemui.monet.ColorScheme;
import com.android.systemui.plugins.ActivityStarter;
@@ -110,6 +111,7 @@
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Executor;
+import java.util.function.Function;
import java.util.stream.Collectors;
/**
@@ -661,28 +663,38 @@
/* connectedMediaDevice */ null,
devices,
needToHandleMutingExpectedDevice);
+ } else {
+ // selected device exist
+ return categorizeMediaItemsLocked(
+ connectedMediaDevice,
+ devices,
+ /* needToHandleMutingExpectedDevice */ false);
}
- // selected device exist
- return categorizeMediaItemsLocked(
- connectedMediaDevice,
- devices,
- /* needToHandleMutingExpectedDevice */ false);
}
// To keep the same list order
final List<MediaDevice> targetMediaDevices = new ArrayList<>();
final Map<Integer, MediaItem> dividerItems = new HashMap<>();
+
+ Map<String, MediaDevice> idToMediaDeviceMap =
+ devices.stream()
+ .collect(Collectors.toMap(MediaDevice::getId, Function.identity()));
+
for (MediaItem originalMediaItem : oldMediaItems) {
- for (MediaDevice newDevice : devices) {
- if (originalMediaItem.getMediaDevice().isPresent()
- && TextUtils.equals(originalMediaItem.getMediaDevice().get().getId(),
- newDevice.getId())) {
- targetMediaDevices.add(newDevice);
- break;
+ switch (originalMediaItem.getMediaItemType()) {
+ case MediaItemType.TYPE_GROUP_DIVIDER -> {
+ dividerItems.put(
+ oldMediaItems.indexOf(originalMediaItem), originalMediaItem);
}
- }
- if (originalMediaItem.getMediaItemType()
- == MediaItem.MediaItemType.TYPE_GROUP_DIVIDER) {
- dividerItems.put(oldMediaItems.indexOf(originalMediaItem), originalMediaItem);
+ case MediaItemType.TYPE_DEVICE -> {
+ String originalMediaItemId =
+ originalMediaItem.getMediaDevice().orElseThrow().getId();
+ if (idToMediaDeviceMap.containsKey(originalMediaItemId)) {
+ targetMediaDevices.add(idToMediaDeviceMap.get(originalMediaItemId));
+ }
+ }
+ case MediaItemType.TYPE_PAIR_NEW_DEVICE -> {
+ // Do nothing.
+ }
}
}
if (targetMediaDevices.size() != devices.size()) {
@@ -723,12 +735,10 @@
finalMediaItems.add(0, MediaItem.createDeviceMediaItem(device));
} else {
if (device.isSuggestedDevice() && !suggestedDeviceAdded) {
- attachGroupDivider(finalMediaItems, mContext.getString(
- R.string.media_output_group_title_suggested_device));
+ addSuggestedDeviceGroupDivider(finalMediaItems);
suggestedDeviceAdded = true;
} else if (!device.isSuggestedDevice() && !displayGroupAdded) {
- attachGroupDivider(finalMediaItems, mContext.getString(
- R.string.media_output_group_title_speakers_and_displays));
+ addSpeakersAndDisplaysGroupDivider(finalMediaItems);
displayGroupAdded = true;
}
finalMediaItems.add(MediaItem.createDeviceMediaItem(device));
@@ -738,8 +748,17 @@
return finalMediaItems;
}
- private void attachGroupDivider(List<MediaItem> mediaItems, String title) {
- mediaItems.add(MediaItem.createGroupDividerMediaItem(title));
+ private void addSuggestedDeviceGroupDivider(List<MediaItem> mediaItems) {
+ mediaItems.add(
+ MediaItem.createGroupDividerMediaItem(
+ mContext.getString(R.string.media_output_group_title_suggested_device)));
+ }
+
+ private void addSpeakersAndDisplaysGroupDivider(List<MediaItem> mediaItems) {
+ mediaItems.add(
+ MediaItem.createGroupDividerMediaItem(
+ mContext.getString(
+ R.string.media_output_group_title_speakers_and_displays)));
}
private void attachConnectNewDeviceItemIfNeeded(List<MediaItem> mediaItems) {
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogManager.kt b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogManager.kt
index ee816942..47e0691 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogManager.kt
@@ -98,7 +98,7 @@
createAndShow(
packageName = null,
aboveStatusBar = false,
- dialogTransitionAnimatorController = null,
+ dialogTransitionAnimatorController = controller,
includePlaybackAndAppMetadata = false,
userHandle = null,
)
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotActionsController.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotActionsController.kt
index 2ffb783..5f16886 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotActionsController.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotActionsController.kt
@@ -18,6 +18,7 @@
import android.app.assist.AssistContent
import com.android.systemui.screenshot.ui.viewmodel.ActionButtonAppearance
+import com.android.systemui.screenshot.ui.viewmodel.PreviewAction
import com.android.systemui.screenshot.ui.viewmodel.ScreenshotViewModel
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
@@ -84,9 +85,9 @@
}
inner class ActionsCallback(private val screenshotId: UUID) {
- fun providePreviewAction(onClick: () -> Unit) {
+ fun providePreviewAction(previewAction: PreviewAction) {
if (screenshotId == currentScreenshotId) {
- viewModel.setPreviewAction(onClick)
+ viewModel.setPreviewAction(previewAction)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotActionsProvider.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotActionsProvider.kt
index b8029c8..c216f1d 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotActionsProvider.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotActionsProvider.kt
@@ -29,6 +29,7 @@
import com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_PREVIEW_TAPPED
import com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_SHARE_TAPPED
import com.android.systemui.screenshot.ui.viewmodel.ActionButtonAppearance
+import com.android.systemui.screenshot.ui.viewmodel.PreviewAction
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
@@ -40,7 +41,9 @@
*/
interface ScreenshotActionsProvider {
fun onScrollChipReady(onClick: Runnable)
+
fun onScrollChipInvalidated()
+
fun setCompletedScreenshot(result: ScreenshotSavedResult)
/**
@@ -75,17 +78,19 @@
private var result: ScreenshotSavedResult? = null
init {
- actionsCallback.providePreviewAction {
- debugLog(LogConfig.DEBUG_ACTIONS) { "Preview tapped" }
- uiEventLogger.log(SCREENSHOT_PREVIEW_TAPPED, 0, request.packageNameString)
- onDeferrableActionTapped { result ->
- actionExecutor.startSharedTransition(
- createEdit(result.uri, context),
- result.user,
- true
- )
+ actionsCallback.providePreviewAction(
+ PreviewAction(context.resources.getString(R.string.screenshot_edit_description)) {
+ debugLog(LogConfig.DEBUG_ACTIONS) { "Preview tapped" }
+ uiEventLogger.log(SCREENSHOT_PREVIEW_TAPPED, 0, request.packageNameString)
+ onDeferrableActionTapped { result ->
+ actionExecutor.startSharedTransition(
+ createEdit(result.uri, context),
+ result.user,
+ true
+ )
+ }
}
- }
+ )
actionsCallback.provideActionButton(
ActionButtonAppearance(
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsActivity.java b/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsActivity.java
index d87d85b..59b47dc 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsActivity.java
@@ -16,16 +16,20 @@
package com.android.systemui.screenshot.appclips;
+import static android.app.ActivityTaskManager.INVALID_TASK_ID;
+
import static com.android.systemui.screenshot.appclips.AppClipsEvent.SCREENSHOT_FOR_NOTE_ACCEPTED;
import static com.android.systemui.screenshot.appclips.AppClipsEvent.SCREENSHOT_FOR_NOTE_CANCELLED;
import static com.android.systemui.screenshot.appclips.AppClipsTrampolineActivity.ACTION_FINISH_FROM_TRAMPOLINE;
import static com.android.systemui.screenshot.appclips.AppClipsTrampolineActivity.EXTRA_CALLING_PACKAGE_NAME;
+import static com.android.systemui.screenshot.appclips.AppClipsTrampolineActivity.EXTRA_CALLING_PACKAGE_TASK_ID;
import static com.android.systemui.screenshot.appclips.AppClipsTrampolineActivity.EXTRA_RESULT_RECEIVER;
import static com.android.systemui.screenshot.appclips.AppClipsTrampolineActivity.EXTRA_SCREENSHOT_URI;
import static com.android.systemui.screenshot.appclips.AppClipsTrampolineActivity.PERMISSION_SELF;
import android.app.Activity;
import android.content.BroadcastReceiver;
+import android.content.ClipData;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
@@ -43,6 +47,7 @@
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
+import android.widget.TextView;
import androidx.activity.ComponentActivity;
import androidx.annotation.Nullable;
@@ -51,10 +56,13 @@
import com.android.internal.logging.UiEventLogger;
import com.android.internal.logging.UiEventLogger.UiEventEnum;
import com.android.settingslib.Utils;
+import com.android.systemui.Flags;
import com.android.systemui.res.R;
import com.android.systemui.screenshot.scroll.CropView;
import com.android.systemui.settings.UserTracker;
+import java.util.Set;
+
import javax.inject.Inject;
/**
@@ -73,8 +81,6 @@
*
* <p>This {@link Activity} runs in its own separate process to isolate memory intensive image
* editing from SysUI process.
- *
- * TODO(b/267309532): Polish UI and animations.
*/
public class AppClipsActivity extends ComponentActivity {
@@ -94,6 +100,7 @@
private CropView mCropView;
private Button mSave;
private Button mCancel;
+ private TextView mBacklinksData;
private AppClipsViewModel mViewModel;
private ResultReceiver mResultReceiver;
@@ -153,11 +160,10 @@
mCancel = mLayout.findViewById(R.id.cancel);
mSave.setOnClickListener(this::onClick);
mCancel.setOnClickListener(this::onClick);
-
-
mCropView = mLayout.findViewById(R.id.crop_view);
-
+ mBacklinksData = mLayout.findViewById(R.id.backlinks_data);
mPreview = mLayout.findViewById(R.id.preview);
+
mPreview.addOnLayoutChangeListener(
(v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) ->
updateImageDimensions());
@@ -166,9 +172,19 @@
mViewModel.getScreenshot().observe(this, this::setScreenshot);
mViewModel.getResultLiveData().observe(this, this::setResultThenFinish);
mViewModel.getErrorLiveData().observe(this, this::setErrorThenFinish);
+ mViewModel.getBacklinksLiveData().observe(this, this::setBacklinksData);
if (savedInstanceState == null) {
- mViewModel.performScreenshot();
+ int displayId = getDisplayId();
+ mViewModel.performScreenshot(displayId);
+
+ if (Flags.appClipsBacklinks()) {
+ int appClipsTaskId = getTaskId();
+ int callingPackageTaskId = intent.getIntExtra(EXTRA_CALLING_PACKAGE_TASK_ID,
+ INVALID_TASK_ID);
+ Set<Integer> taskIdsToIgnore = Set.of(appClipsTaskId, callingPackageTaskId);
+ mViewModel.triggerBacklinks(taskIdsToIgnore, displayId);
+ }
}
}
@@ -281,6 +297,15 @@
finish();
}
+ private void setBacklinksData(ClipData clipData) {
+ if (mBacklinksData.getVisibility() == View.GONE) {
+ mBacklinksData.setVisibility(View.VISIBLE);
+ }
+
+ mBacklinksData.setText(String.format(getString(R.string.backlinks_string),
+ clipData.getDescription().getLabel()));
+ }
+
private void setError(int errorCode) {
if (mResultReceiver == null) {
return;
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsCrossProcessHelper.java b/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsCrossProcessHelper.java
index 7de22b1..aaa5dfc 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsCrossProcessHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsCrossProcessHelper.java
@@ -20,6 +20,7 @@
import android.content.Intent;
import android.graphics.Bitmap;
import android.os.UserHandle;
+import android.util.Log;
import androidx.annotation.Nullable;
@@ -27,19 +28,18 @@
import com.android.internal.infra.ServiceConnector;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Application;
-import com.android.systemui.settings.DisplayTracker;
import javax.inject.Inject;
/** An intermediary singleton object to help communicating with the cross process service. */
@SysUISingleton
class AppClipsCrossProcessHelper {
+ private static final String TAG = AppClipsCrossProcessHelper.class.getSimpleName();
private final ServiceConnector<IAppClipsScreenshotHelperService> mProxyConnector;
- private final DisplayTracker mDisplayTracker;
@Inject
- AppClipsCrossProcessHelper(@Application Context context, DisplayTracker displayTracker) {
+ AppClipsCrossProcessHelper(@Application Context context) {
// Start a service as main user so that even if the app clips activity is running as work
// profile user the service is able to use correct instance of Bubbles to grab a screenshot
// excluding the bubble layer.
@@ -48,7 +48,6 @@
Context.BIND_AUTO_CREATE | Context.BIND_WAIVE_PRIORITY
| Context.BIND_NOT_VISIBLE, UserHandle.USER_SYSTEM,
IAppClipsScreenshotHelperService.Stub::asInterface);
- mDisplayTracker = displayTracker;
}
/**
@@ -58,15 +57,16 @@
* pass around but not a {@link Bitmap}.
*/
@Nullable
- Bitmap takeScreenshot() {
+ Bitmap takeScreenshot(int displayId) {
try {
AndroidFuture<ScreenshotHardwareBufferInternal> future =
mProxyConnector.postForResult(
- service ->
- // Take a screenshot of the default display of the user.
- service.takeScreenshot(mDisplayTracker.getDefaultDisplayId()));
+ service -> service.takeScreenshot(displayId));
return future.get().createBitmapThenCloseBuffer();
} catch (Exception e) {
+ Log.e(TAG,
+ String.format("Error while capturing a screenshot of displayId %d", displayId),
+ e);
return null;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsTrampolineActivity.java b/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsTrampolineActivity.java
index 48449b3..3c4469d 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsTrampolineActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsTrampolineActivity.java
@@ -85,6 +85,7 @@
static final String ACTION_FINISH_FROM_TRAMPOLINE = TAG + "FINISH_FROM_TRAMPOLINE";
static final String EXTRA_RESULT_RECEIVER = TAG + "RESULT_RECEIVER";
static final String EXTRA_CALLING_PACKAGE_NAME = TAG + "CALLING_PACKAGE_NAME";
+ static final String EXTRA_CALLING_PACKAGE_TASK_ID = TAG + "CALLING_PACKAGE_TASK_ID";
private static final ApplicationInfoFlags APPLICATION_INFO_FLAGS = ApplicationInfoFlags.of(0);
private final NoteTaskController mNoteTaskController;
@@ -193,12 +194,14 @@
ComponentName componentName = ComponentName.unflattenFromString(
getString(R.string.config_screenshotAppClipsActivityComponent));
String callingPackageName = getCallingPackage();
+ int callingPackageTaskId = getTaskId();
Intent intent = new Intent()
.setComponent(componentName)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
.putExtra(EXTRA_RESULT_RECEIVER, mResultReceiver)
- .putExtra(EXTRA_CALLING_PACKAGE_NAME, callingPackageName);
+ .putExtra(EXTRA_CALLING_PACKAGE_NAME, callingPackageName)
+ .putExtra(EXTRA_CALLING_PACKAGE_TASK_ID, callingPackageTaskId);
try {
startActivity(intent);
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsViewModel.java b/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsViewModel.java
index 630d338..9bb7bbf 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsViewModel.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsViewModel.java
@@ -16,9 +16,23 @@
package com.android.systemui.screenshot.appclips;
+import static android.content.Intent.ACTION_MAIN;
+import static android.content.Intent.ACTION_VIEW;
import static android.content.Intent.CAPTURE_CONTENT_FOR_NOTE_FAILED;
+import static android.content.Intent.CATEGORY_LAUNCHER;
+import static com.google.common.util.concurrent.Futures.withTimeout;
+
+import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
+
+import android.app.ActivityTaskManager.RootTaskInfo;
+import android.app.IActivityTaskManager;
+import android.app.WindowConfiguration;
+import android.app.assist.AssistContent;
+import android.content.ClipData;
+import android.content.ComponentName;
import android.content.Intent;
+import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.HardwareRenderer;
import android.graphics.RecordingCanvas;
@@ -26,10 +40,13 @@
import android.graphics.RenderNode;
import android.graphics.drawable.Drawable;
import android.net.Uri;
+import android.os.RemoteException;
import android.os.UserHandle;
+import android.util.Log;
import android.view.Display;
import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
@@ -37,22 +54,36 @@
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.screenshot.AssistContentRequester;
import com.android.systemui.screenshot.ImageExporter;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.SettableFuture;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
+import java.util.concurrent.TimeUnit;
import javax.inject.Inject;
/** A {@link ViewModel} to help with the App Clips screenshot flow. */
final class AppClipsViewModel extends ViewModel {
+ private static final String TAG = AppClipsViewModel.class.getSimpleName();
+
private final AppClipsCrossProcessHelper mAppClipsCrossProcessHelper;
private final ImageExporter mImageExporter;
+ private final IActivityTaskManager mAtmService;
+ private final AssistContentRequester mAssistContentRequester;
+ private final PackageManager mPackageManager;
+
@Main
private final Executor mMainExecutor;
@Background
@@ -61,24 +92,34 @@
private final MutableLiveData<Bitmap> mScreenshotLiveData;
private final MutableLiveData<Uri> mResultLiveData;
private final MutableLiveData<Integer> mErrorLiveData;
+ private final MutableLiveData<ClipData> mBacklinksLiveData;
- AppClipsViewModel(AppClipsCrossProcessHelper appClipsCrossProcessHelper,
- ImageExporter imageExporter, @Main Executor mainExecutor,
- @Background Executor bgExecutor) {
+ private AppClipsViewModel(AppClipsCrossProcessHelper appClipsCrossProcessHelper,
+ ImageExporter imageExporter, IActivityTaskManager atmService,
+ AssistContentRequester assistContentRequester, PackageManager packageManager,
+ @Main Executor mainExecutor, @Background Executor bgExecutor) {
mAppClipsCrossProcessHelper = appClipsCrossProcessHelper;
mImageExporter = imageExporter;
+ mAtmService = atmService;
+ mAssistContentRequester = assistContentRequester;
+ mPackageManager = packageManager;
mMainExecutor = mainExecutor;
mBgExecutor = bgExecutor;
mScreenshotLiveData = new MutableLiveData<>();
mResultLiveData = new MutableLiveData<>();
mErrorLiveData = new MutableLiveData<>();
+ mBacklinksLiveData = new MutableLiveData<>();
}
- /** Grabs a screenshot and updates the {@link Bitmap} set in screenshot {@link LiveData}. */
- void performScreenshot() {
+ /**
+ * Grabs a screenshot and updates the {@link Bitmap} set in screenshot {@link #getScreenshot()}.
+ *
+ * @param displayId id of the {@link Display} to capture screenshot.
+ */
+ void performScreenshot(int displayId) {
mBgExecutor.execute(() -> {
- Bitmap screenshot = mAppClipsCrossProcessHelper.takeScreenshot();
+ Bitmap screenshot = mAppClipsCrossProcessHelper.takeScreenshot(displayId);
mMainExecutor.execute(() -> {
if (screenshot == null) {
mErrorLiveData.setValue(CAPTURE_CONTENT_FOR_NOTE_FAILED);
@@ -89,6 +130,38 @@
});
}
+ /**
+ * Triggers the Backlinks flow which:
+ * <ul>
+ * <li>Evaluates the task to query.
+ * <li>Requests {@link AssistContent} from that task.
+ * <li>Transforms the {@link AssistContent} into {@link ClipData} for Backlinks.
+ * <li>The {@link ClipData} is reported to activity via {@link #getBacklinksLiveData()}.
+ * </ul>
+ *
+ * @param taskIdsToIgnore id of the tasks to ignore when querying for {@link AssistContent}
+ * @param displayId id of the display to query tasks for Backlinks data
+ */
+ void triggerBacklinks(Set<Integer> taskIdsToIgnore, int displayId) {
+ mBgExecutor.execute(() -> {
+ ListenableFuture<ClipData> backlinksData = getBacklinksData(taskIdsToIgnore, displayId);
+ Futures.addCallback(backlinksData, new FutureCallback<>() {
+ @Override
+ public void onSuccess(@Nullable ClipData result) {
+ if (result != null) {
+ mBacklinksLiveData.setValue(result);
+ }
+ }
+
+ @Override
+ public void onFailure(Throwable t) {
+ Log.e(TAG, "Error querying for Backlinks data", t);
+ }
+ }, mMainExecutor);
+
+ });
+ }
+
/** Returns a {@link LiveData} that holds the captured screenshot. */
LiveData<Bitmap> getScreenshot() {
return mScreenshotLiveData;
@@ -107,6 +180,11 @@
return mErrorLiveData;
}
+ /** Returns a {@link LiveData} that holds the Backlinks data in {@link ClipData}. */
+ LiveData<ClipData> getBacklinksLiveData() {
+ return mBacklinksLiveData;
+ }
+
/**
* Saves the provided {@link Drawable} to storage then informs the result {@link Uri} to
* {@link LiveData}.
@@ -148,21 +226,144 @@
return HardwareRenderer.createHardwareBitmap(output, bounds.width(), bounds.height());
}
+ private ListenableFuture<ClipData> getBacklinksData(Set<Integer> taskIdsToIgnore,
+ int displayId) {
+ return getAllRootTaskInfosOnDisplay(displayId)
+ .stream()
+ .filter(taskInfo -> shouldIncludeTask(taskInfo, taskIdsToIgnore))
+ .findFirst()
+ .map(this::getBacklinksDataForTaskId)
+ .orElse(Futures.immediateFuture(null));
+ }
+
+ private List<RootTaskInfo> getAllRootTaskInfosOnDisplay(int displayId) {
+ try {
+ return mAtmService.getAllRootTaskInfosOnDisplay(displayId);
+ } catch (RemoteException e) {
+ Log.e(TAG, String.format("Error while querying for tasks on display %d", displayId), e);
+ return Collections.emptyList();
+ }
+ }
+
+ private boolean shouldIncludeTask(RootTaskInfo taskInfo, Set<Integer> taskIdsToIgnore) {
+ // Only consider tasks that shouldn't be ignored, are visible, running, and have a launcher
+ // icon. Furthermore, types such as launcher/home/dock/assistant are ignored.
+ return !taskIdsToIgnore.contains(taskInfo.taskId)
+ && taskInfo.isVisible
+ && taskInfo.isRunning
+ && taskInfo.numActivities > 0
+ && taskInfo.topActivity != null
+ && taskInfo.topActivityInfo != null
+ && taskInfo.childTaskIds.length > 0
+ && taskInfo.getActivityType() == WindowConfiguration.ACTIVITY_TYPE_STANDARD
+ && canAppStartThroughLauncher(taskInfo.topActivity.getPackageName());
+ }
+
+ private boolean canAppStartThroughLauncher(String packageName) {
+ return getMainLauncherIntentForPackage(packageName).resolveActivity(mPackageManager)
+ != null;
+ }
+
+ private ListenableFuture<ClipData> getBacklinksDataForTaskId(RootTaskInfo taskInfo) {
+ SettableFuture<ClipData> backlinksData = SettableFuture.create();
+ int taskId = taskInfo.taskId;
+ mAssistContentRequester.requestAssistContent(taskId, assistContent ->
+ backlinksData.set(getBacklinksDataFromAssistContent(taskInfo, assistContent)));
+ return withTimeout(backlinksData, 5L, TimeUnit.SECONDS, newSingleThreadScheduledExecutor());
+ }
+
+ /**
+ * A utility method to get {@link ClipData} to use for Backlinks functionality from
+ * {@link AssistContent} received from the app whose screenshot is taken.
+ *
+ * <p>There are multiple ways an app can provide deep-linkable data via {@link AssistContent}
+ * but Backlinks restricts to using only one way. The following is the ordered list based on
+ * preference:
+ * <ul>
+ * <li>{@link AssistContent#getWebUri()} is the most preferred way.
+ * <li>Second preference is given to {@link AssistContent#getIntent()} when the app provides
+ * the intent, see {@link AssistContent#isAppProvidedIntent()}.
+ * <li>The last preference is given to an {@link Intent} that is built using
+ * {@link Intent#ACTION_MAIN} and {@link Intent#CATEGORY_LAUNCHER}.
+ * </ul>
+ *
+ * @param taskInfo {@link RootTaskInfo} of the task which provided the {@link AssistContent}.
+ * @param content the {@link AssistContent} to map into Backlinks {@link ClipData}.
+ * @return {@link ClipData} that represents the Backlinks data.
+ */
+ private ClipData getBacklinksDataFromAssistContent(RootTaskInfo taskInfo,
+ @Nullable AssistContent content) {
+ String appName = getAppNameOfTask(taskInfo);
+ String packageName = taskInfo.topActivity.getPackageName();
+ ClipData fallback = ClipData.newIntent(appName,
+ getMainLauncherIntentForPackage(packageName));
+ if (content == null) {
+ return fallback;
+ }
+
+ // First preference is given to app provided uri.
+ if (content.isAppProvidedWebUri()) {
+ Uri uri = content.getWebUri();
+ Intent backlinksIntent = new Intent(ACTION_VIEW).setData(uri);
+ if (doesIntentResolveToSamePackage(backlinksIntent, packageName)) {
+ return ClipData.newRawUri(appName, uri);
+ }
+ }
+
+ // Second preference is given to app provided, hopefully deep-linking, intent.
+ if (content.isAppProvidedIntent()) {
+ Intent backlinksIntent = content.getIntent();
+ if (doesIntentResolveToSamePackage(backlinksIntent, packageName)) {
+ return ClipData.newIntent(appName, backlinksIntent);
+ }
+ }
+
+ return fallback;
+ }
+
+ private boolean doesIntentResolveToSamePackage(Intent intentToResolve,
+ String requiredPackageName) {
+ ComponentName resolvedComponent = intentToResolve.resolveActivity(mPackageManager);
+ if (resolvedComponent == null) {
+ return false;
+ }
+
+ return resolvedComponent.getPackageName().equals(requiredPackageName);
+ }
+
+ private String getAppNameOfTask(RootTaskInfo taskInfo) {
+ return taskInfo.topActivityInfo.loadLabel(mPackageManager).toString();
+ }
+
+ private Intent getMainLauncherIntentForPackage(String packageName) {
+ return new Intent(ACTION_MAIN)
+ .addCategory(CATEGORY_LAUNCHER)
+ .setPackage(packageName);
+ }
+
/** Helper factory to help with injecting {@link AppClipsViewModel}. */
static final class Factory implements ViewModelProvider.Factory {
private final AppClipsCrossProcessHelper mAppClipsCrossProcessHelper;
private final ImageExporter mImageExporter;
+ private final IActivityTaskManager mAtmService;
+ private final AssistContentRequester mAssistContentRequester;
+ private final PackageManager mPackageManager;
@Main
private final Executor mMainExecutor;
@Background
private final Executor mBgExecutor;
@Inject
- Factory(AppClipsCrossProcessHelper appClipsCrossProcessHelper, ImageExporter imageExporter,
- @Main Executor mainExecutor, @Background Executor bgExecutor) {
+ Factory(AppClipsCrossProcessHelper appClipsCrossProcessHelper, ImageExporter imageExporter,
+ IActivityTaskManager atmService, AssistContentRequester assistContentRequester,
+ PackageManager packageManager, @Main Executor mainExecutor,
+ @Background Executor bgExecutor) {
mAppClipsCrossProcessHelper = appClipsCrossProcessHelper;
mImageExporter = imageExporter;
+ mAtmService = atmService;
+ mAssistContentRequester = assistContentRequester;
+ mPackageManager = packageManager;
mMainExecutor = mainExecutor;
mBgExecutor = bgExecutor;
}
@@ -176,7 +377,8 @@
//noinspection unchecked
return (T) new AppClipsViewModel(mAppClipsCrossProcessHelper, mImageExporter,
- mMainExecutor, mBgExecutor);
+ mAtmService, mAssistContentRequester, mPackageManager, mMainExecutor,
+ mBgExecutor);
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ui/binder/ScreenshotShelfViewBinder.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ui/binder/ScreenshotShelfViewBinder.kt
index 442b387..0fefa0b 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ui/binder/ScreenshotShelfViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ui/binder/ScreenshotShelfViewBinder.kt
@@ -128,8 +128,9 @@
}
}
launch {
- viewModel.previewAction.collect { onClick ->
- previewView.setOnClickListener { onClick?.invoke() }
+ viewModel.previewAction.collect { action ->
+ previewView.setOnClickListener { action?.onClick?.invoke() }
+ previewView.contentDescription = action?.contentDescription
}
}
launch {
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ui/viewmodel/ScreenshotViewModel.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ui/viewmodel/ScreenshotViewModel.kt
index 3f99bc4..25420d4 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ui/viewmodel/ScreenshotViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ui/viewmodel/ScreenshotViewModel.kt
@@ -31,8 +31,8 @@
val scrollingScrim: StateFlow<Bitmap?> = _scrollingScrim
private val _badge = MutableStateFlow<Drawable?>(null)
val badge: StateFlow<Drawable?> = _badge
- private val _previewAction = MutableStateFlow<(() -> Unit)?>(null)
- val previewAction: StateFlow<(() -> Unit)?> = _previewAction
+ private val _previewAction = MutableStateFlow<PreviewAction?>(null)
+ val previewAction: StateFlow<PreviewAction?> = _previewAction
private val _actions = MutableStateFlow(emptyList<ActionButtonViewModel>())
val actions: StateFlow<List<ActionButtonViewModel>> = _actions
private val _animationState = MutableStateFlow(AnimationState.NOT_STARTED)
@@ -57,8 +57,8 @@
_badge.value = badge
}
- fun setPreviewAction(onClick: () -> Unit) {
- _previewAction.value = onClick
+ fun setPreviewAction(previewAction: PreviewAction) {
+ _previewAction.value = previewAction
}
fun addAction(
@@ -149,6 +149,11 @@
}
}
+data class PreviewAction(
+ val contentDescription: CharSequence,
+ val onClick: () -> Unit,
+)
+
enum class AnimationState {
NOT_STARTED,
ENTRANCE_STARTED, // The first 200ms of the entrance animation
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index 9624e0f..1d43ec2 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -1044,6 +1044,10 @@
mView.setTranslationY(0f);
})
.start();
+ } else {
+ mView.postDelayed(() -> {
+ instantCollapse();
+ }, unlockAnimationStartDelay);
}
}
}
@@ -3390,7 +3394,9 @@
/** Updates the views to the initial state for the fold to AOD animation. */
@Override
public void prepareFoldToAodAnimation() {
- if (!MigrateClocksToBlueprint.isEnabled()) {
+ if (MigrateClocksToBlueprint.isEnabled()) {
+ setDozing(true /* dozing */, false /* animate */);
+ } else {
// Force show AOD UI even if we are not locked
showAodUi();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 95cabfb..1a7871a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -386,6 +386,11 @@
mStatusBarStateListener.onDozingChanged(mStatusBarStateController.isDozing());
}
+ @Nullable
+ public ViewGroup getIndicationArea() {
+ return mIndicationArea;
+ }
+
public void setIndicationArea(ViewGroup indicationArea) {
mIndicationArea = indicationArea;
mTopIndicationView = indicationArea.findViewById(R.id.keyguard_indication_text);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModel.kt
index ad09aa3..ba3fde6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModel.kt
@@ -24,6 +24,7 @@
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.res.R
import com.android.systemui.statusbar.chips.call.domain.interactor.CallChipInteractor
+import com.android.systemui.statusbar.chips.ui.model.ColorsModel
import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel
import com.android.systemui.statusbar.chips.ui.view.ChipBackgroundContainer
import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipViewModel
@@ -65,6 +66,7 @@
com.android.internal.R.drawable.ic_phone,
contentDescription = null,
),
+ colors = ColorsModel.Themed,
startTimeMs = startTimeInElapsedRealtime,
) {
if (state.intent != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/casttootherdevice/ui/viewmodel/CastToOtherDeviceChipViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/casttootherdevice/ui/viewmodel/CastToOtherDeviceChipViewModel.kt
index a1678bf..53b1e75 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/casttootherdevice/ui/viewmodel/CastToOtherDeviceChipViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/casttootherdevice/ui/viewmodel/CastToOtherDeviceChipViewModel.kt
@@ -27,6 +27,7 @@
import com.android.systemui.statusbar.chips.mediaprojection.domain.interactor.MediaProjectionChipInteractor
import com.android.systemui.statusbar.chips.mediaprojection.domain.model.ProjectionChipModel
import com.android.systemui.statusbar.chips.mediaprojection.ui.view.EndMediaProjectionDialogHelper
+import com.android.systemui.statusbar.chips.ui.model.ColorsModel
import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel
import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipViewModel
import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipViewModel.Companion.createDialogLaunchOnClickListener
@@ -85,6 +86,7 @@
CAST_TO_OTHER_DEVICE_ICON,
ContentDescription.Resource(R.string.accessibility_casting),
),
+ colors = ColorsModel.Red,
// TODO(b/332662551): Maybe use a MediaProjection API to fetch this time.
startTimeMs = systemClock.elapsedRealtime(),
createDialogLaunchOnClickListener(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/screenrecord/ui/viewmodel/ScreenRecordChipViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/screenrecord/ui/viewmodel/ScreenRecordChipViewModel.kt
index d190cfd..9d54c75 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/screenrecord/ui/viewmodel/ScreenRecordChipViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/screenrecord/ui/viewmodel/ScreenRecordChipViewModel.kt
@@ -27,6 +27,7 @@
import com.android.systemui.statusbar.chips.screenrecord.domain.interactor.ScreenRecordChipInteractor
import com.android.systemui.statusbar.chips.screenrecord.domain.model.ScreenRecordChipModel
import com.android.systemui.statusbar.chips.screenrecord.ui.view.EndScreenRecordingDialogDelegate
+import com.android.systemui.statusbar.chips.ui.model.ColorsModel
import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel
import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipViewModel
import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipViewModel.Companion.createDialogLaunchOnClickListener
@@ -60,6 +61,7 @@
OngoingActivityChipModel.Shown(
// TODO(b/332662551): Also provide a content description.
icon = Icon.Resource(ICON, contentDescription = null),
+ colors = ColorsModel.Red,
startTimeMs = systemClock.elapsedRealtime(),
createDialogLaunchOnClickListener(
createDelegate(state.recordedTask),
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/sharetoapp/ui/viewmodel/ShareToAppChipViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/sharetoapp/ui/viewmodel/ShareToAppChipViewModel.kt
index dc41002..0c24a70 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/sharetoapp/ui/viewmodel/ShareToAppChipViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/sharetoapp/ui/viewmodel/ShareToAppChipViewModel.kt
@@ -26,6 +26,7 @@
import com.android.systemui.statusbar.chips.mediaprojection.domain.model.ProjectionChipModel
import com.android.systemui.statusbar.chips.mediaprojection.ui.view.EndMediaProjectionDialogHelper
import com.android.systemui.statusbar.chips.sharetoapp.ui.view.EndShareToAppDialogDelegate
+import com.android.systemui.statusbar.chips.ui.model.ColorsModel
import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel
import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipViewModel
import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipViewModel.Companion.createDialogLaunchOnClickListener
@@ -78,6 +79,7 @@
return OngoingActivityChipModel.Shown(
// TODO(b/332662551): Use the right content description.
icon = Icon.Resource(SHARE_TO_APP_ICON, contentDescription = null),
+ colors = ColorsModel.Red,
// TODO(b/332662551): Maybe use a MediaProjection API to fetch this time.
startTimeMs = systemClock.elapsedRealtime(),
createDialogLaunchOnClickListener(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/model/ColorsModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/model/ColorsModel.kt
new file mode 100644
index 0000000..b2140f7
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/model/ColorsModel.kt
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.chips.ui.model
+
+import android.content.Context
+import android.content.res.ColorStateList
+import androidx.annotation.ColorInt
+import com.android.settingslib.Utils
+import com.android.systemui.res.R
+
+/** Model representing how the chip in the status bar should be colored. */
+sealed interface ColorsModel {
+ /** The color for the background of the chip. */
+ fun background(context: Context): ColorStateList
+
+ /** The color for the text (and icon) on the chip. */
+ @ColorInt fun text(context: Context): Int
+
+ /** The chip should match the theme's primary color. */
+ data object Themed : ColorsModel {
+ override fun background(context: Context): ColorStateList =
+ Utils.getColorAttr(context, com.android.internal.R.attr.colorAccent)
+
+ override fun text(context: Context) =
+ Utils.getColorAttrDefaultColor(context, com.android.internal.R.attr.colorPrimary)
+ }
+
+ /** The chip should have a red background with white text. */
+ data object Red : ColorsModel {
+ override fun background(context: Context): ColorStateList =
+ ColorStateList.valueOf(context.getColor(R.color.GM2_red_600))
+
+ override fun text(context: Context) = context.getColor(android.R.color.white)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/model/OngoingActivityChipModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/model/OngoingActivityChipModel.kt
index e63713b..4ea674a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/model/OngoingActivityChipModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/model/OngoingActivityChipModel.kt
@@ -28,6 +28,8 @@
data class Shown(
/** The icon to show on the chip. */
val icon: Icon,
+ /** What colors to use for the chip. */
+ val colors: ColorsModel,
/**
* The time this event started, used to show the timer.
*
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/VisualStabilityProvider.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/VisualStabilityProvider.kt
index 5adf31b..f166d32 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/VisualStabilityProvider.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/VisualStabilityProvider.kt
@@ -13,12 +13,18 @@
/** The subset of active listeners which are temporary (will be removed after called) */
private val temporaryListeners = ArraySet<OnReorderingAllowedListener>()
+ private val banListeners = ListenerSet<OnReorderingBannedListener>()
+
var isReorderingAllowed = true
set(value) {
if (field != value) {
field = value
if (value) {
notifyReorderingAllowed()
+ } else {
+ banListeners.forEach { listener ->
+ listener.onReorderingBanned()
+ }
}
}
}
@@ -38,6 +44,10 @@
allListeners.addIfAbsent(listener)
}
+ fun addPersistentReorderingBannedListener(listener: OnReorderingBannedListener) {
+ banListeners.addIfAbsent(listener)
+ }
+
/** Add a listener which will be removed when it is called. */
fun addTemporaryReorderingAllowedListener(listener: OnReorderingAllowedListener) {
// Only add to the temporary set if it was added to the global set
@@ -57,3 +67,8 @@
fun interface OnReorderingAllowedListener {
fun onReorderingAllowed()
}
+
+fun interface OnReorderingBannedListener {
+ fun onReorderingBanned()
+}
+
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index 190a2cd..4ba673d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -2011,6 +2011,21 @@
};
}
+ /**
+ * Retrieves an OnClickListener for the close button of a notification, which when invoked,
+ * dismisses the notificationc represented by the given ExpandableNotificationRow.
+ *
+ * @param row The ExpandableNotificationRow representing the notification to be dismissed.
+ * @return An OnClickListener instance that dismisses the notification(s) when invoked.
+ */
+ public View.OnClickListener getCloseButtonOnClickListener(ExpandableNotificationRow row) {
+ return v -> {
+ if (row != null) {
+ row.performDismiss(false);
+ }
+ };
+ }
+
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
Trace.beginSection(appendTraceStyleTag("ExpNotRow#onMeasure"));
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java
index 9394249..f352123 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java
@@ -36,6 +36,7 @@
import com.android.app.animation.Interpolators;
import com.android.internal.widget.CachingIconView;
+import com.android.internal.widget.NotificationCloseButton;
import com.android.internal.widget.NotificationExpandButton;
import com.android.systemui.res.R;
import com.android.systemui.statusbar.TransformableView;
@@ -60,6 +61,7 @@
= new PathInterpolator(0.4f, 0f, 0.7f, 1f);
protected final ViewTransformationHelper mTransformationHelper;
private CachingIconView mIcon;
+ private NotificationCloseButton mCloseButton;
private NotificationExpandButton mExpandButton;
private View mAltExpandTarget;
private View mIconContainer;
@@ -112,6 +114,7 @@
TRANSFORMING_VIEW_TITLE);
resolveHeaderViews();
addFeedbackOnClickListener(row);
+ addCloseButtonOnClickListener(row);
}
@Override
@@ -150,6 +153,7 @@
mNotificationTopLine = mView.findViewById(com.android.internal.R.id.notification_top_line);
mAudiblyAlertedIcon = mView.findViewById(com.android.internal.R.id.alerted_icon);
mFeedbackIcon = mView.findViewById(com.android.internal.R.id.feedback);
+ mCloseButton = mView.findViewById(com.android.internal.R.id.close_button);
}
private void addFeedbackOnClickListener(ExpandableNotificationRow row) {
@@ -179,6 +183,13 @@
}
}
+ private void addCloseButtonOnClickListener(ExpandableNotificationRow row) {
+ View.OnClickListener listener = row.getCloseButtonOnClickListener(row);
+ if (mCloseButton != null && listener != null) {
+ mCloseButton.setOnClickListener(listener);
+ }
+ }
+
@Override
public void onContentUpdated(ExpandableNotificationRow row) {
super.onContentUpdated(row);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 0e77ed4..38bcc0b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -1181,9 +1181,11 @@
updateAlgorithmLayoutMinHeight();
updateOwnTranslationZ();
- // Give The Algorithm information regarding the QS height so it can layout notifications
- // properly. Needed for some devices that grows notifications down-to-top
- mStackScrollAlgorithm.updateQSFrameTop(mQsHeader == null ? 0 : mQsHeader.getHeight());
+ if (!SceneContainerFlag.isEnabled()) {
+ // Give The Algorithm information regarding the QS height so it can layout notifications
+ // properly. Needed for some devices that grows notifications down-to-top
+ mStackScrollAlgorithm.updateQSFrameTop(mQsHeader == null ? 0 : mQsHeader.getHeight());
+ }
// Once the layout has finished, we don't need to animate any scrolling clampings anymore.
mAnimateStackYForContentHeightChange = false;
@@ -1811,6 +1813,7 @@
}
public void setQsHeader(ViewGroup qsHeader) {
+ SceneContainerFlag.assertInLegacyMode();
mQsHeader = qsHeader;
}
@@ -2662,6 +2665,7 @@
}
public void setMaxTopPadding(int maxTopPadding) {
+ SceneContainerFlag.assertInLegacyMode();
mMaxTopPadding = maxTopPadding;
}
@@ -2682,6 +2686,7 @@
}
public float getTopPaddingOverflow() {
+ SceneContainerFlag.assertInLegacyMode();
return mTopPaddingOverflow;
}
@@ -4641,6 +4646,7 @@
}
public boolean isEmptyShadeViewVisible() {
+ SceneContainerFlag.assertInLegacyMode();
return mEmptyShadeView.isVisible();
}
@@ -4919,6 +4925,7 @@
}
public void setQsFullScreen(boolean qsFullScreen) {
+ SceneContainerFlag.assertInLegacyMode();
if (FooterViewRefactor.isEnabled()) {
if (qsFullScreen == mQsFullScreen) {
return; // no change
@@ -5095,6 +5102,7 @@
}
public void setExpandingVelocity(float expandingVelocity) {
+ SceneContainerFlag.assertInLegacyMode();
mAmbientState.setExpandingVelocity(expandingVelocity);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
index 62c139b..5c262f3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -1481,7 +1481,9 @@
return (v, event) -> {
mAutoHideController.checkUserAutoHide(event);
mRemoteInputManager.checkRemoteInputOutside(event);
- if (!MigrateClocksToBlueprint.isEnabled()) {
+ if (!MigrateClocksToBlueprint.isEnabled() || mQsController.isCustomizing()) {
+ // For migrate clocks flag, when the user is editing QS tiles they need to be able
+ // to touch outside the customizer to close it, such as on the status or nav bar.
mShadeController.onStatusBarTouch(event);
}
return getNotificationShadeWindowView().onTouchEvent(event);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
index 3925beb..c5dcb09 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
@@ -39,6 +39,7 @@
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.provider.OnReorderingAllowedListener;
+import com.android.systemui.statusbar.notification.collection.provider.OnReorderingBannedListener;
import com.android.systemui.statusbar.notification.collection.provider.VisualStabilityProvider;
import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
import com.android.systemui.statusbar.notification.data.repository.HeadsUpRepository;
@@ -86,7 +87,7 @@
private final List<OnHeadsUpPhoneListenerChange> mHeadsUpPhoneListeners = new ArrayList<>();
private final VisualStabilityProvider mVisualStabilityProvider;
- private final AvalancheController mAvalancheController;
+ private AvalancheController mAvalancheController;
// TODO(b/328393698) move the topHeadsUpRow logic to an interactor
private final MutableStateFlow<HeadsUpRowRepository> mTopHeadsUpRow =
@@ -175,6 +176,7 @@
javaAdapter.alwaysCollectFlow(shadeInteractor.isAnyExpanded(),
this::onShadeOrQsExpanded);
}
+ mVisualStabilityProvider.addPersistentReorderingBannedListener(mOnReorderingBannedListener);
}
public void setAnimationStateHandler(AnimationStateHandler handler) {
@@ -382,6 +384,8 @@
private final OnReorderingAllowedListener mOnReorderingAllowedListener = () -> {
mAnimationStateHandler.setHeadsUpGoingAwayAnimationsAllowed(false);
+ mAvalancheController.setEnableAtRuntime(true);
+
for (NotificationEntry entry : mEntriesToRemoveWhenReorderingAllowed) {
if (isHeadsUpEntry(entry.getKey())) {
// Maybe the heads-up was removed already
@@ -392,6 +396,28 @@
mAnimationStateHandler.setHeadsUpGoingAwayAnimationsAllowed(true);
};
+ private final OnReorderingBannedListener mOnReorderingBannedListener = () -> {
+ if (mAvalancheController != null) {
+ // Waiting HUNs in AvalancheController are still promoted to the HUN section and thus
+ // seen in open shade; clear them so we don't show them again when the shade closes and
+ // reordering is allowed again.
+ mAvalancheController.logDroppedHuns(mAvalancheController.getWaitingKeys().size());
+ mAvalancheController.clearNext();
+
+ // In open shade the first HUN is pinned, and visual stability logic prevents us from
+ // unpinning this first HUN as long as the shade remains open. AvalancheController only
+ // shows the next HUN when the currently showing HUN is unpinned, so we must disable
+ // throttling here so that the incoming HUN stream is not forever paused. This is reset
+ // when reorder becomes allowed.
+ mAvalancheController.setEnableAtRuntime(false);
+
+ // Note that we cannot do the above when
+ // 1) the remove runnable runs because its delay means it may not run before shade close
+ // 2) reordering is allowed again (when shade closes) because the HUN appear animation
+ // will have started by then
+ }
+ };
+
///////////////////////////////////////////////////////////////////////////////////////////////
// HeadsUpManager utility (protected) methods overrides:
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java
index 4b1ee58..0218784 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java
@@ -68,7 +68,7 @@
private final UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
private boolean mIsStatusBarExpanded = false;
- private boolean mIsIdleOnGone = false;
+ private boolean mIsIdleOnGone = true;
private boolean mShouldAdjustInsets = false;
private View mNotificationShadeWindowView;
private View mNotificationPanelView;
@@ -282,7 +282,7 @@
// since we don't want stray touches to go through the light reveal scrim to whatever is
// underneath.
return mIsStatusBarExpanded
- || !mIsIdleOnGone
+ || (SceneContainerFlag.isEnabled() && !mIsIdleOnGone)
|| mPrimaryBouncerInteractor.isShowing().getValue()
|| mAlternateBouncerInteractor.isVisibleState()
|| mUnlockedScreenOffAnimationController.isAnimationPlaying();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/DeviceBasedSatelliteRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/DeviceBasedSatelliteRepositoryImpl.kt
index ec3af87..a7c5f78 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/DeviceBasedSatelliteRepositoryImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/DeviceBasedSatelliteRepositoryImpl.kt
@@ -345,32 +345,67 @@
orElse = flowOf(false),
retrySignal = telephonyProcessCrashedEvent,
)
- .stateIn(scope, SharingStarted.WhileSubscribed(), false)
+ .stateIn(scope, SharingStarted.Eagerly, false)
private fun satelliteProvisioned(sm: SupportedSatelliteManager): Flow<Boolean> =
conflatedCallbackFlow {
- val callback = SatelliteProvisionStateCallback { provisioned ->
- logBuffer.i {
- "onSatelliteProvisionStateChanged: " +
- if (provisioned) "provisioned" else "not provisioned"
+ // TODO(b/347992038): SatelliteManager should be sending the current provisioned
+ // status when we register a callback. Until then, we have to manually query here.
+
+ // First, check to see what the current status is, and send the result to the output
+ trySend(queryIsSatelliteProvisioned(sm))
+
+ val callback = SatelliteProvisionStateCallback { provisioned ->
+ logBuffer.i {
+ "onSatelliteProvisionStateChanged: " +
+ if (provisioned) "provisioned" else "not provisioned"
+ }
+ trySend(provisioned)
}
- trySend(provisioned)
- }
- var registered = false
- try {
- sm.registerForProvisionStateChanged(
- bgDispatcher.asExecutor(),
- callback,
- )
- registered = true
- } catch (e: Exception) {
- logBuffer.e("error registering for provisioning state callback", e)
- }
+ var registered = false
+ try {
+ logBuffer.i { "registerForProvisionStateChanged" }
+ sm.registerForProvisionStateChanged(
+ bgDispatcher.asExecutor(),
+ callback,
+ )
+ registered = true
+ } catch (e: Exception) {
+ logBuffer.e("error registering for provisioning state callback", e)
+ }
- awaitClose {
- if (registered) {
- sm.unregisterForProvisionStateChanged(callback)
+ awaitClose {
+ if (registered) {
+ sm.unregisterForProvisionStateChanged(callback)
+ }
+ }
+ }
+ .flowOn(bgDispatcher)
+
+ /** Check the current satellite provisioning status. */
+ private suspend fun queryIsSatelliteProvisioned(sm: SupportedSatelliteManager): Boolean =
+ withContext(bgDispatcher) {
+ suspendCancellableCoroutine { continuation ->
+ val receiver =
+ object : OutcomeReceiver<Boolean, SatelliteManager.SatelliteException> {
+ override fun onResult(result: Boolean) {
+ logBuffer.i { "requestIsProvisioned.onResult: $result" }
+ continuation.resume(result)
+ }
+
+ override fun onError(exception: SatelliteManager.SatelliteException) {
+ logBuffer.e("requestIsProvisioned.onError:", exception)
+ continuation.resume(false)
+ }
+ }
+
+ logBuffer.i { "Query for current satellite provisioned state." }
+ try {
+ sm.requestIsProvisioned(bgDispatcher.asExecutor(), receiver)
+ } catch (e: Exception) {
+ logBuffer.e("Exception while calling SatelliteManager.requestIsProvisioned:", e)
+ continuation.resume(false)
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/CollapsedStatusBarViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/CollapsedStatusBarViewBinder.kt
index 7644653..d607ce0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/CollapsedStatusBarViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/CollapsedStatusBarViewBinder.kt
@@ -18,6 +18,8 @@
import android.animation.Animator
import android.animation.AnimatorListenerAdapter
+import android.content.res.ColorStateList
+import android.graphics.drawable.GradientDrawable
import android.view.View
import android.widget.ImageView
import androidx.lifecycle.Lifecycle
@@ -29,6 +31,7 @@
import com.android.systemui.res.R
import com.android.systemui.statusbar.chips.ui.binder.ChipChronometerBinder
import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel
+import com.android.systemui.statusbar.chips.ui.view.ChipBackgroundContainer
import com.android.systemui.statusbar.chips.ui.view.ChipChronometer
import com.android.systemui.statusbar.notification.shared.NotificationsLiveDataStoreRefactor
import com.android.systemui.statusbar.pipeline.shared.ui.viewmodel.CollapsedStatusBarViewModel
@@ -84,18 +87,31 @@
if (Flags.statusBarScreenSharingChips()) {
val chipView: View = view.requireViewById(R.id.ongoing_activity_chip)
+ val chipContext = chipView.context
val chipIconView: ImageView =
chipView.requireViewById(R.id.ongoing_activity_chip_icon)
val chipTimeView: ChipChronometer =
chipView.requireViewById(R.id.ongoing_activity_chip_time)
+ val chipBackgroundView =
+ chipView.requireViewById<ChipBackgroundContainer>(
+ R.id.ongoing_activity_chip_background
+ )
launch {
viewModel.ongoingActivityChip.collect { chipModel ->
when (chipModel) {
is OngoingActivityChipModel.Shown -> {
+ // Data
IconViewBinder.bind(chipModel.icon, chipIconView)
ChipChronometerBinder.bind(chipModel.startTimeMs, chipTimeView)
chipView.setOnClickListener(chipModel.onClickListener)
+ // Colors
+ val textColor = chipModel.colors.text(chipContext)
+ chipIconView.imageTintList = ColorStateList.valueOf(textColor)
+ chipTimeView.setTextColor(textColor)
+ (chipBackgroundView.background as GradientDrawable).color =
+ chipModel.colors.background(chipContext)
+
listener.onOngoingActivityStatusChanged(
hasOngoingActivity = true
)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AvalancheController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AvalancheController.kt
index 32774e0..dbe54f3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AvalancheController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AvalancheController.kt
@@ -39,6 +39,7 @@
private val tag = "AvalancheController"
private val debug = Compile.IS_DEBUG && Log.isLoggable(tag, Log.DEBUG)
+ var enableAtRuntime = true
// HUN showing right now, in the floating state where full shade is hidden, on launcher or AOD
@VisibleForTesting var headsUpEntryShowing: HeadsUpEntry? = null
@@ -81,13 +82,17 @@
dumpManager.registerNormalDumpable(tag, /* module */ this)
}
+ fun isEnabled() : Boolean {
+ return NotificationThrottleHun.isEnabled && enableAtRuntime
+ }
+
fun getShowingHunKey(): String {
return getKey(headsUpEntryShowing)
}
/** Run or delay Runnable for given HeadsUpEntry */
fun update(entry: HeadsUpEntry?, runnable: Runnable, label: String) {
- if (!NotificationThrottleHun.isEnabled) {
+ if (!isEnabled()) {
runnable.run()
return
}
@@ -143,7 +148,7 @@
* all Runnables associated with that entry.
*/
fun delete(entry: HeadsUpEntry?, runnable: Runnable, label: String) {
- if (!NotificationThrottleHun.isEnabled) {
+ if (!isEnabled()) {
runnable.run()
return
}
@@ -184,7 +189,7 @@
* BaseHeadsUpManager.HeadsUpEntry.calculateFinishTime to shorten display duration.
*/
fun getDurationMs(entry: HeadsUpEntry, autoDismissMs: Int): Int {
- if (!NotificationThrottleHun.isEnabled) {
+ if (!isEnabled()) {
// Use default duration, like we did before AvalancheController existed
return autoDismissMs
}
@@ -233,7 +238,7 @@
/** Return true if entry is waiting to show. */
fun isWaiting(key: String): Boolean {
- if (!NotificationThrottleHun.isEnabled) {
+ if (!isEnabled()) {
return false
}
for (entry in nextMap.keys) {
@@ -246,7 +251,7 @@
/** Return list of keys for huns waiting */
fun getWaitingKeys(): MutableList<String> {
- if (!NotificationThrottleHun.isEnabled) {
+ if (!isEnabled()) {
return mutableListOf()
}
val keyList = mutableListOf<String>()
@@ -257,7 +262,7 @@
}
fun getWaitingEntry(key: String): HeadsUpEntry? {
- if (!NotificationThrottleHun.isEnabled) {
+ if (!isEnabled()) {
return null
}
for (headsUpEntry in nextMap.keys) {
@@ -269,7 +274,7 @@
}
fun getWaitingEntryList(): List<HeadsUpEntry> {
- if (!NotificationThrottleHun.isEnabled) {
+ if (!isEnabled()) {
return mutableListOf()
}
return nextMap.keys.toList()
@@ -310,11 +315,7 @@
// Remove runnable labels for dropped huns
val listToDrop = nextList.subList(1, nextList.size)
-
- // Log dropped HUNs
- for (e in listToDrop) {
- uiEventLogger.log(ThrottleEvent.AVALANCHE_THROTTLING_HUN_DROPPED)
- }
+ logDroppedHuns(listToDrop.size)
if (debug) {
// Clear runnable labels
@@ -331,6 +332,12 @@
showNow(headsUpEntryShowing!!, headsUpEntryShowingRunnableList)
}
+ fun logDroppedHuns(numDropped: Int) {
+ for (n in 1..numDropped) {
+ uiEventLogger.log(ThrottleEvent.AVALANCHE_THROTTLING_HUN_DROPPED)
+ }
+ }
+
fun clearNext() {
nextList.clear()
nextMap.clear()
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/domain/interactor/TouchpadGesturesInteractor.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/domain/interactor/TouchpadGesturesInteractor.kt
new file mode 100644
index 0000000..b6c2ae7
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/domain/interactor/TouchpadGesturesInteractor.kt
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.touchpad.tutorial.domain.interactor
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.model.SysUiState
+import com.android.systemui.settings.DisplayTracker
+import com.android.systemui.shared.system.QuickStepContract
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.launch
+
+@SysUISingleton
+class TouchpadGesturesInteractor
+@Inject
+constructor(
+ private val sysUiState: SysUiState,
+ private val displayTracker: DisplayTracker,
+ @Background private val backgroundScope: CoroutineScope
+) {
+ fun disableGestures() {
+ setGesturesState(disabled = true)
+ }
+
+ fun enableGestures() {
+ setGesturesState(disabled = false)
+ }
+
+ private fun setGesturesState(disabled: Boolean) {
+ backgroundScope.launch {
+ sysUiState
+ .setFlag(QuickStepContract.SYSUI_STATE_TOUCHPAD_GESTURES_DISABLED, disabled)
+ .commitUpdate(displayTracker.defaultDisplayId)
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/TouchpadTutorialViewModel.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/TouchpadTutorialViewModel.kt
index 11740a8..9e6553a 100644
--- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/TouchpadTutorialViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/TouchpadTutorialViewModel.kt
@@ -18,11 +18,13 @@
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
+import com.android.systemui.touchpad.tutorial.domain.interactor.TouchpadGesturesInteractor
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import javax.inject.Inject
-class TouchpadTutorialViewModel : ViewModel() {
+class TouchpadTutorialViewModel(private val gesturesInteractor: TouchpadGesturesInteractor) :
+ ViewModel() {
private val _screen = MutableStateFlow(Screen.TUTORIAL_SELECTION)
val screen: StateFlow<Screen> = _screen
@@ -31,11 +33,20 @@
_screen.value = screen
}
- class Factory @Inject constructor() : ViewModelProvider.Factory {
+ fun onOpened() {
+ gesturesInteractor.disableGestures()
+ }
+
+ fun onClosed() {
+ gesturesInteractor.enableGestures()
+ }
+
+ class Factory @Inject constructor(private val gesturesInteractor: TouchpadGesturesInteractor) :
+ ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(modelClass: Class<T>): T {
- return TouchpadTutorialViewModel() as T
+ return TouchpadTutorialViewModel(gesturesInteractor) as T
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/view/BackGestureTutorialScreen.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/view/BackGestureTutorialScreen.kt
new file mode 100644
index 0000000..2460761c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/view/BackGestureTutorialScreen.kt
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.touchpad.tutorial.ui.view
+
+import androidx.activity.compose.BackHandler
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.width
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.unit.dp
+import com.android.systemui.res.R
+
+@Composable
+fun BackGestureTutorialScreen(
+ onDoneButtonClicked: () -> Unit,
+ onBack: () -> Unit,
+ modifier: Modifier = Modifier,
+) {
+ BackHandler { onBack() }
+ Column(
+ verticalArrangement = Arrangement.Center,
+ modifier =
+ modifier
+ .background(color = MaterialTheme.colorScheme.surfaceContainer)
+ .padding(start = 48.dp, top = 124.dp, end = 48.dp, bottom = 48.dp)
+ .fillMaxSize()
+ ) {
+ Row(modifier = Modifier.fillMaxWidth().weight(1f)) {
+ TutorialDescription(modifier = Modifier.weight(1f))
+ Spacer(modifier = Modifier.width(76.dp))
+ TutorialAnimation(modifier = Modifier.weight(1f).padding(top = 24.dp))
+ }
+ DoneButton(onDoneButtonClicked = onDoneButtonClicked)
+ }
+}
+
+@Composable
+fun TutorialDescription(modifier: Modifier = Modifier) {
+ Column(verticalArrangement = Arrangement.Top, modifier = modifier) {
+ Text(
+ text = stringResource(id = R.string.touchpad_back_gesture_action_title),
+ style = MaterialTheme.typography.displayLarge
+ )
+ Spacer(modifier = Modifier.height(16.dp))
+ Text(
+ text = stringResource(id = R.string.touchpad_back_gesture_guidance),
+ style = MaterialTheme.typography.bodyLarge
+ )
+ }
+}
+
+@Composable
+fun TutorialAnimation(modifier: Modifier = Modifier) {
+ // below are just placeholder images, will be substituted by animations soon
+ Column(modifier = modifier.fillMaxWidth()) {
+ Image(
+ painter = painterResource(id = R.drawable.placeholder_touchpad_tablet_back_gesture),
+ contentDescription =
+ stringResource(
+ id = R.string.touchpad_back_gesture_screen_animation_content_description
+ ),
+ modifier = Modifier.fillMaxWidth()
+ )
+ Spacer(modifier = Modifier.height(24.dp))
+ Image(
+ painter = painterResource(id = R.drawable.placeholder_touchpad_back_gesture),
+ contentDescription =
+ stringResource(id = R.string.touchpad_back_gesture_animation_content_description),
+ modifier = Modifier.fillMaxWidth()
+ )
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/view/TouchpadTutorialActivity.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/view/TouchpadTutorialActivity.kt
index b7629c7..0c5c187 100644
--- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/view/TouchpadTutorialActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/view/TouchpadTutorialActivity.kt
@@ -20,14 +20,13 @@
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
+import androidx.activity.viewModels
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.lifecycle.Lifecycle.State.STARTED
-import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.viewmodel.compose.viewModel
import com.android.compose.theme.PlatformTheme
-import com.android.systemui.touchpad.tutorial.ui.BackGestureTutorialViewModel
import com.android.systemui.touchpad.tutorial.ui.GestureViewModelFactory
import com.android.systemui.touchpad.tutorial.ui.HomeGestureTutorialViewModel
import com.android.systemui.touchpad.tutorial.ui.Screen.BACK_GESTURE
@@ -42,18 +41,27 @@
private val viewModelFactory: TouchpadTutorialViewModel.Factory,
) : ComponentActivity() {
+ private val vm by viewModels<TouchpadTutorialViewModel>(factoryProducer = { viewModelFactory })
+
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
- setContent {
- PlatformTheme { TouchpadTutorialScreen(viewModelFactory, closeTutorial = { finish() }) }
- }
+ setContent { PlatformTheme { TouchpadTutorialScreen(vm) { finish() } } }
+ }
+
+ override fun onResume() {
+ super.onResume()
+ vm.onOpened()
+ }
+
+ override fun onPause() {
+ super.onPause()
+ vm.onClosed()
}
}
@Composable
-fun TouchpadTutorialScreen(viewModelFactory: ViewModelProvider.Factory, closeTutorial: () -> Unit) {
- val vm = viewModel<TouchpadTutorialViewModel>(factory = viewModelFactory)
+fun TouchpadTutorialScreen(vm: TouchpadTutorialViewModel, closeTutorial: () -> Unit) {
val activeScreen by vm.screen.collectAsStateWithLifecycle(STARTED)
when (activeScreen) {
TUTORIAL_SELECTION ->
@@ -63,17 +71,16 @@
onActionKeyTutorialClicked = {},
onDoneButtonClicked = closeTutorial
)
- BACK_GESTURE -> BackGestureTutorialScreen()
+ BACK_GESTURE ->
+ BackGestureTutorialScreen(
+ onDoneButtonClicked = { vm.goTo(TUTORIAL_SELECTION) },
+ onBack = { vm.goTo(TUTORIAL_SELECTION) }
+ )
HOME_GESTURE -> HomeGestureTutorialScreen()
}
}
@Composable
-fun BackGestureTutorialScreen() {
- val vm = viewModel<BackGestureTutorialViewModel>(factory = GestureViewModelFactory())
-}
-
-@Composable
fun HomeGestureTutorialScreen() {
val vm = viewModel<HomeGestureTutorialViewModel>(factory = GestureViewModelFactory())
}
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/view/TutorialComponents.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/view/TutorialComponents.kt
new file mode 100644
index 0000000..16fa91d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/view/TutorialComponents.kt
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.touchpad.tutorial.ui.view
+
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.material3.Button
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.res.stringResource
+import com.android.systemui.res.R
+
+@Composable
+fun DoneButton(onDoneButtonClicked: () -> Unit, modifier: Modifier = Modifier) {
+ Row(
+ horizontalArrangement = Arrangement.End,
+ verticalAlignment = Alignment.CenterVertically,
+ modifier = modifier.fillMaxWidth()
+ ) {
+ Button(onClick = onDoneButtonClicked) {
+ Text(stringResource(R.string.touchpad_tutorial_done_button))
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/view/TutorialSelectionScreen.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/view/TutorialSelectionScreen.kt
index 532eb1b..877bbe1 100644
--- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/view/TutorialSelectionScreen.kt
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/view/TutorialSelectionScreen.kt
@@ -22,7 +22,6 @@
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxSize
-import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Button
@@ -114,16 +113,3 @@
Text(text = text, style = MaterialTheme.typography.headlineLarge)
}
}
-
-@Composable
-private fun DoneButton(onDoneButtonClicked: () -> Unit, modifier: Modifier = Modifier) {
- Row(
- horizontalArrangement = Arrangement.End,
- verticalAlignment = Alignment.CenterVertically,
- modifier = modifier.fillMaxWidth()
- ) {
- Button(onClick = onDoneButtonClicked) {
- Text(stringResource(R.string.touchpad_tutorial_done_button))
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/unfold/FoldLightRevealOverlayAnimation.kt b/packages/SystemUI/src/com/android/systemui/unfold/FoldLightRevealOverlayAnimation.kt
index aea739d..9faa84e 100644
--- a/packages/SystemUI/src/com/android/systemui/unfold/FoldLightRevealOverlayAnimation.kt
+++ b/packages/SystemUI/src/com/android/systemui/unfold/FoldLightRevealOverlayAnimation.kt
@@ -22,9 +22,12 @@
import android.annotation.BinderThread
import android.os.SystemProperties
import android.util.Log
+import android.view.View
import android.view.animation.DecelerateInterpolator
import com.android.app.tracing.TraceUtils.traceAsync
import com.android.internal.foldables.FoldLockSettingAvailabilityProvider
+import com.android.internal.jank.Cuj.CUJ_FOLD_ANIM
+import com.android.internal.jank.InteractionJankMonitor
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.display.data.repository.DeviceStateRepository
import com.android.systemui.power.domain.interactor.PowerInteractor
@@ -65,7 +68,8 @@
@Background private val applicationScope: CoroutineScope,
private val animationStatusRepository: AnimationStatusRepository,
private val controllerFactory: FullscreenLightRevealAnimationController.Factory,
- private val foldLockSettingAvailabilityProvider: FoldLockSettingAvailabilityProvider
+ private val foldLockSettingAvailabilityProvider: FoldLockSettingAvailabilityProvider,
+ private val interactionJankMonitor: InteractionJankMonitor
) : FullscreenLightRevealAnimation {
private val revealProgressValueAnimator: ValueAnimator =
@@ -149,13 +153,23 @@
private suspend fun waitForGoToSleep() =
traceAsync(TAG, "waitForGoToSleep()") { powerInteractor.isAsleep.filter { it }.first() }
- private suspend fun playFoldLightRevealOverlayAnimation() {
- revealProgressValueAnimator.duration = ANIMATION_DURATION
- revealProgressValueAnimator.interpolator = DecelerateInterpolator()
- revealProgressValueAnimator.addUpdateListener { animation ->
- controller.updateRevealAmount(animation.animatedFraction)
+ private suspend fun playFoldLightRevealOverlayAnimation() =
+ trackCuj(CUJ_FOLD_ANIM, controller.scrimView) {
+ revealProgressValueAnimator.duration = ANIMATION_DURATION
+ revealProgressValueAnimator.interpolator = DecelerateInterpolator()
+ revealProgressValueAnimator.addUpdateListener { animation ->
+ controller.updateRevealAmount(animation.animatedFraction)
+ }
+ revealProgressValueAnimator.startAndAwaitCompletion()
}
- revealProgressValueAnimator.startAndAwaitCompletion()
+
+ private suspend fun trackCuj(cuj: Int, view: View?, block: suspend () -> Unit) {
+ view?.let { interactionJankMonitor.begin(it, cuj) }
+ try {
+ block()
+ } finally {
+ if (view != null) interactionJankMonitor.end(cuj)
+ }
}
private suspend fun ValueAnimator.startAndAwaitCompletion(): Unit =
diff --git a/packages/SystemUI/src/com/android/systemui/unfold/FullscreenLightRevealAnimation.kt b/packages/SystemUI/src/com/android/systemui/unfold/FullscreenLightRevealAnimation.kt
index 135edfc..f368cac 100644
--- a/packages/SystemUI/src/com/android/systemui/unfold/FullscreenLightRevealAnimation.kt
+++ b/packages/SystemUI/src/com/android/systemui/unfold/FullscreenLightRevealAnimation.kt
@@ -81,7 +81,10 @@
private var currentRotation: Int = context.display.rotation
private var root: SurfaceControlViewHost? = null
- private var scrimView: LightRevealScrim? = null
+
+ /** The scrim view that is used to reveal the screen. */
+ var scrimView: LightRevealScrim? = null
+ private set
private val rotationWatcher = RotationWatcher()
private val internalDisplayInfos: List<DisplayInfo> =
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/spatial/domain/interactor/SpatialAudioComponentInteractor.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/spatial/domain/interactor/SpatialAudioComponentInteractor.kt
index 7f1faee..cfcd6b1 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/spatial/domain/interactor/SpatialAudioComponentInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/spatial/domain/interactor/SpatialAudioComponentInteractor.kt
@@ -16,15 +16,23 @@
package com.android.systemui.volume.panel.component.spatial.domain.interactor
+import android.bluetooth.BluetoothProfile
import android.media.AudioDeviceAttributes
import android.media.AudioDeviceInfo
+import android.media.AudioManager
+import com.android.settingslib.bluetooth.CachedBluetoothDevice
+import com.android.settingslib.bluetooth.LocalBluetoothProfile
+import com.android.settingslib.flags.Flags
import com.android.settingslib.media.domain.interactor.SpatializerInteractor
+import com.android.settingslib.volume.data.repository.AudioRepository
+import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.volume.domain.interactor.AudioOutputInteractor
import com.android.systemui.volume.domain.model.AudioOutputDevice
import com.android.systemui.volume.panel.component.spatial.domain.model.SpatialAudioAvailabilityModel
import com.android.systemui.volume.panel.component.spatial.domain.model.SpatialAudioEnabledModel
import com.android.systemui.volume.panel.dagger.scope.VolumePanelScope
import javax.inject.Inject
+import kotlin.coroutines.CoroutineContext
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.SharingStarted
@@ -33,6 +41,7 @@
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.withContext
/**
* Provides an ability to access and update spatial audio and head tracking state.
@@ -46,6 +55,8 @@
constructor(
audioOutputInteractor: AudioOutputInteractor,
private val spatializerInteractor: SpatializerInteractor,
+ private val audioRepository: AudioRepository,
+ @Background private val backgroundCoroutineContext: CoroutineContext,
@VolumePanelScope private val coroutineScope: CoroutineScope,
) {
@@ -138,42 +149,85 @@
}
private suspend fun AudioOutputDevice.getAudioDeviceAttributes(): AudioDeviceAttributes? {
- when (this) {
- is AudioOutputDevice.BuiltIn -> return builtinSpeaker
+ return when (this) {
+ is AudioOutputDevice.BuiltIn -> builtinSpeaker
is AudioOutputDevice.Bluetooth -> {
- return listOf(
- AudioDeviceAttributes(
- AudioDeviceAttributes.ROLE_OUTPUT,
- AudioDeviceInfo.TYPE_BLE_HEADSET,
- cachedBluetoothDevice.address,
- ),
- AudioDeviceAttributes(
- AudioDeviceAttributes.ROLE_OUTPUT,
- AudioDeviceInfo.TYPE_BLE_SPEAKER,
- cachedBluetoothDevice.address,
- ),
- AudioDeviceAttributes(
- AudioDeviceAttributes.ROLE_OUTPUT,
- AudioDeviceInfo.TYPE_BLE_BROADCAST,
- cachedBluetoothDevice.address,
- ),
- AudioDeviceAttributes(
- AudioDeviceAttributes.ROLE_OUTPUT,
- AudioDeviceInfo.TYPE_BLUETOOTH_A2DP,
- cachedBluetoothDevice.address,
- ),
- AudioDeviceAttributes(
- AudioDeviceAttributes.ROLE_OUTPUT,
- AudioDeviceInfo.TYPE_HEARING_AID,
- cachedBluetoothDevice.address,
+ if (Flags.enableDeterminingSpatialAudioAttributesByProfile()) {
+ getAudioDeviceAttributesByBluetoothProfile(cachedBluetoothDevice)
+ } else {
+ listOf(
+ AudioDeviceAttributes(
+ AudioDeviceAttributes.ROLE_OUTPUT,
+ AudioDeviceInfo.TYPE_BLE_HEADSET,
+ cachedBluetoothDevice.address,
+ ),
+ AudioDeviceAttributes(
+ AudioDeviceAttributes.ROLE_OUTPUT,
+ AudioDeviceInfo.TYPE_BLE_SPEAKER,
+ cachedBluetoothDevice.address,
+ ),
+ AudioDeviceAttributes(
+ AudioDeviceAttributes.ROLE_OUTPUT,
+ AudioDeviceInfo.TYPE_BLE_BROADCAST,
+ cachedBluetoothDevice.address,
+ ),
+ AudioDeviceAttributes(
+ AudioDeviceAttributes.ROLE_OUTPUT,
+ AudioDeviceInfo.TYPE_BLUETOOTH_A2DP,
+ cachedBluetoothDevice.address,
+ ),
+ AudioDeviceAttributes(
+ AudioDeviceAttributes.ROLE_OUTPUT,
+ AudioDeviceInfo.TYPE_HEARING_AID,
+ cachedBluetoothDevice.address,
+ )
)
- )
- .firstOrNull { spatializerInteractor.isSpatialAudioAvailable(it) }
+ .firstOrNull { spatializerInteractor.isSpatialAudioAvailable(it) }
+ }
}
- else -> return null
+ else -> null
}
}
+ private suspend fun getAudioDeviceAttributesByBluetoothProfile(
+ cachedBluetoothDevice: CachedBluetoothDevice
+ ): AudioDeviceAttributes? =
+ withContext(backgroundCoroutineContext) {
+ cachedBluetoothDevice.profiles
+ .firstOrNull {
+ it.profileId in audioProfiles && it.isEnabled(cachedBluetoothDevice.device)
+ }
+ ?.let { profile: LocalBluetoothProfile ->
+ when (profile.profileId) {
+ BluetoothProfile.A2DP -> {
+ AudioDeviceInfo.TYPE_BLUETOOTH_A2DP
+ }
+ BluetoothProfile.LE_AUDIO -> {
+ when (
+ audioRepository.getBluetoothAudioDeviceCategory(
+ cachedBluetoothDevice.address
+ )
+ ) {
+ AudioManager.AUDIO_DEVICE_CATEGORY_SPEAKER ->
+ AudioDeviceInfo.TYPE_BLE_SPEAKER
+ else -> AudioDeviceInfo.TYPE_BLE_HEADSET
+ }
+ }
+ BluetoothProfile.HEARING_AID -> {
+ AudioDeviceInfo.TYPE_HEARING_AID
+ }
+ else -> null
+ }
+ }
+ ?.let {
+ AudioDeviceAttributes(
+ AudioDeviceAttributes.ROLE_OUTPUT,
+ it,
+ cachedBluetoothDevice.address,
+ )
+ }
+ }
+
private companion object {
val builtinSpeaker =
AudioDeviceAttributes(
@@ -181,5 +235,7 @@
AudioDeviceInfo.TYPE_BUILTIN_SPEAKER,
""
)
+ val audioProfiles =
+ setOf(BluetoothProfile.A2DP, BluetoothProfile.LE_AUDIO, BluetoothProfile.HEARING_AID)
}
}
diff --git a/packages/SystemUI/tests/src/androidx/core/animation/AnimatorTestRuleIsolationTest.kt b/packages/SystemUI/tests/src/androidx/core/animation/AnimatorTestRuleIsolationTest.kt
index 2d84fba..5b3f08f 100644
--- a/packages/SystemUI/tests/src/androidx/core/animation/AnimatorTestRuleIsolationTest.kt
+++ b/packages/SystemUI/tests/src/androidx/core/animation/AnimatorTestRuleIsolationTest.kt
@@ -15,8 +15,8 @@
*/
package androidx.core.animation
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.util.doOnEnd
@@ -29,7 +29,7 @@
* This test class validates that two tests' animators are isolated from each other when using the
* same animator test rule. This is a test to prevent future instances of b/275602127.
*/
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
@RunWithLooper
class AnimatorTestRuleIsolationTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/AuthKeyguardMessageAreaTest.java b/packages/SystemUI/tests/src/com/android/keyguard/AuthKeyguardMessageAreaTest.java
index 52af8fb..6ee8ffd 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/AuthKeyguardMessageAreaTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/AuthKeyguardMessageAreaTest.java
@@ -18,10 +18,10 @@
import static com.google.common.truth.Truth.assertThat;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper.RunWithLooper;
import android.view.View;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -32,7 +32,7 @@
import org.mockito.MockitoAnnotations;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@RunWithLooper
public class AuthKeyguardMessageAreaTest extends SysuiTestCase {
private KeyguardMessageArea mKeyguardMessageArea;
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/BouncerKeyguardMessageAreaTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/BouncerKeyguardMessageAreaTest.kt
index ba46a87..049d77a 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/BouncerKeyguardMessageAreaTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/BouncerKeyguardMessageAreaTest.kt
@@ -17,9 +17,9 @@
package com.android.keyguard
import android.content.Context
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
import android.util.AttributeSet
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.google.common.truth.Truth.assertThat
@@ -31,7 +31,7 @@
import org.mockito.Mockito.verify
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@RunWithLooper
class BouncerKeyguardMessageAreaTest : SysuiTestCase() {
class FakeBouncerKeyguardMessageArea(context: Context, attrs: AttributeSet?) :
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/BouncerPanelExpansionCalculatorTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/BouncerPanelExpansionCalculatorTest.kt
index 6512e70..bb2340a 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/BouncerPanelExpansionCalculatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/BouncerPanelExpansionCalculatorTest.kt
@@ -16,15 +16,15 @@
package com.android.keyguard
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
-import android.testing.AndroidTestingRunner
import com.android.systemui.SysuiTestCase
import com.google.common.truth.Truth.assertThat
import org.junit.Assert.assertEquals
import org.junit.Test
import org.junit.runner.RunWith
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
class BouncerPanelExpansionCalculatorTest : SysuiTestCase() {
@Test
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextManagerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextManagerTest.java
index 0a3225e..a8ab922 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextManagerTest.java
@@ -50,9 +50,9 @@
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
-import android.testing.AndroidTestingRunner;
import android.text.TextUtils;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.keyguard.logging.CarrierTextManagerLogger;
@@ -84,7 +84,7 @@
import java.util.List;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
public class CarrierTextManagerTest extends SysuiTestCase {
private static final CharSequence SEPARATOR = " \u2014 ";
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
index 69a6f2a..79933ee 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
@@ -16,10 +16,10 @@
package com.android.keyguard
import android.content.BroadcastReceiver
-import android.testing.AndroidTestingRunner
import android.view.View
import android.view.ViewTreeObserver
import android.widget.FrameLayout
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.broadcast.BroadcastDispatcher
@@ -76,7 +76,7 @@
import com.android.systemui.Flags as AConfigFlags
import org.mockito.Mockito.`when` as whenever
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
class ClockEventControllerTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/EmergencyButtonControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/EmergencyButtonControllerTest.kt
index 9a95b17..347605d 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/EmergencyButtonControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/EmergencyButtonControllerTest.kt
@@ -21,8 +21,8 @@
import android.os.PowerManager
import android.telecom.TelecomManager
import android.telephony.TelephonyManager
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.internal.logging.MetricsLogger
import com.android.internal.widget.LockPatternUtils
@@ -45,7 +45,7 @@
import org.mockito.MockitoAnnotations
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@TestableLooper.RunWithLooper
class EmergencyButtonControllerTest : SysuiTestCase() {
@Mock lateinit var emergencyButton: EmergencyButton
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java
index f9fe5e7..e724c60 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java
@@ -28,10 +28,10 @@
import android.os.SystemClock;
import android.platform.test.annotations.EnableFlags;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper.RunWithLooper;
import android.view.KeyEvent;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.internal.util.LatencyTracker;
@@ -54,7 +54,7 @@
import org.mockito.MockitoAnnotations;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@RunWithLooper
public class KeyguardAbsKeyInputViewControllerTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardBiometricLockoutLoggerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardBiometricLockoutLoggerTest.kt
index 634dac1..d170e48 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardBiometricLockoutLoggerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardBiometricLockoutLoggerTest.kt
@@ -17,7 +17,7 @@
package com.android.keyguard
import android.hardware.biometrics.BiometricSourceType
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.internal.logging.InstanceId
import com.android.internal.logging.UiEventLogger
@@ -38,7 +38,7 @@
import org.mockito.MockitoAnnotations
import org.mockito.Mockito.`when` as whenever
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
class KeyguardBiometricLockoutLoggerTest : SysuiTestCase() {
@Mock
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
index cfa74f0..1d78168 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
@@ -30,9 +30,9 @@
import android.database.ContentObserver;
import android.os.UserHandle;
import android.provider.Settings;
-import android.testing.AndroidTestingRunner;
import android.view.View;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.Flags;
@@ -47,7 +47,7 @@
import org.mockito.verification.VerificationMode;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
public class KeyguardClockSwitchControllerTest extends KeyguardClockSwitchControllerBaseTest {
@Test
public void testInit_viewAlreadyAttached() {
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerWithCoroutinesTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerWithCoroutinesTest.kt
index 9a1a4e2..c2c0f57 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerWithCoroutinesTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerWithCoroutinesTest.kt
@@ -16,8 +16,8 @@
package com.android.keyguard
-import android.testing.AndroidTestingRunner
import android.view.View
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.flags.Flags.LOCKSCREEN_WALLPAPER_DREAM_ENABLED
import kotlinx.coroutines.Dispatchers
@@ -26,7 +26,7 @@
import org.junit.Test
import org.junit.runner.RunWith
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
class KeyguardClockSwitchControllerWithCoroutinesTest : KeyguardClockSwitchControllerBaseTest() {
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java
index e2063d2..83443be 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java
@@ -30,7 +30,6 @@
import static org.mockito.Mockito.when;
import android.content.Context;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper.RunWithLooper;
import android.util.AttributeSet;
import android.view.LayoutInflater;
@@ -39,6 +38,7 @@
import android.widget.FrameLayout;
import android.widget.TextView;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.Flags;
@@ -55,7 +55,7 @@
import org.mockito.MockitoAnnotations;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
// Need to run on the main thread because KeyguardSliceView$Row init checks for
// the main thread before acquiring a wake lock. This class is constructed when
// the keyguard_clock_switch layout is inflated.
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardDisplayManagerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardDisplayManagerTest.java
index cc36cfa..dd58ea7 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardDisplayManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardDisplayManagerTest.java
@@ -28,11 +28,11 @@
import static org.mockito.Mockito.when;
import android.hardware.display.DisplayManagerGlobal;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.Display;
import android.view.DisplayInfo;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -49,7 +49,7 @@
import java.util.concurrent.Executor;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper
public class KeyguardDisplayManagerTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaControllerTest.java
index 6228ff8..bd81181 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaControllerTest.java
@@ -27,11 +27,11 @@
import static org.mockito.Mockito.when;
import android.hardware.biometrics.BiometricSourceType;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.text.Editable;
import android.text.TextWatcher;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -47,7 +47,7 @@
@SmallTest
@TestableLooper.RunWithLooper
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
public class KeyguardMessageAreaControllerTest extends SysuiTestCase {
@Mock
private ConfigurationController mConfigurationController;
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewControllerTest.java
index c566826..8b5372a 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewControllerTest.java
@@ -23,11 +23,11 @@
import android.content.pm.PackageManager;
import android.os.Handler;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
import android.view.View;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -47,7 +47,7 @@
import org.mockito.MockitoAnnotations;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@RunWithLooper(setAsMainLooper = true)
public class KeyguardSliceViewControllerTest extends SysuiTestCase {
@Mock
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewTest.java
index a0e8065..d96518a 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewTest.java
@@ -17,7 +17,6 @@
import android.graphics.Color;
import android.net.Uri;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper.RunWithLooper;
import android.view.LayoutInflater;
@@ -26,6 +25,7 @@
import androidx.slice.SliceSpecs;
import androidx.slice.builders.ListBuilder;
import androidx.slice.widget.RowContent;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -44,7 +44,7 @@
@SmallTest
@RunWithLooper(setAsMainLooper = true)
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
public class KeyguardSliceViewTest extends SysuiTestCase {
private KeyguardSliceView mKeyguardSliceView;
private Uri mSliceUri;
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusAreaViewTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusAreaViewTest.kt
index ed61ee12..64e4996 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusAreaViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusAreaViewTest.kt
@@ -1,7 +1,7 @@
package com.android.keyguard
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import org.junit.Assert.assertEquals
@@ -10,7 +10,7 @@
import org.junit.runner.RunWith
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@RunWithLooper(setAsMainLooper = true)
class KeyguardStatusAreaViewTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerWithCoroutinesTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerWithCoroutinesTest.kt
index 3b57d8f..c29439d 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerWithCoroutinesTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerWithCoroutinesTest.kt
@@ -16,8 +16,8 @@
package com.android.keyguard
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.power.shared.model.ScreenPowerState
import kotlinx.coroutines.cancelChildren
@@ -29,7 +29,7 @@
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
@SmallTest
class KeyguardStatusViewControllerWithCoroutinesTest : KeyguardStatusViewControllerBaseTest() {
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.kt
index afd2034..16d2f02 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.kt
@@ -1,7 +1,7 @@
package com.android.keyguard
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
import android.view.LayoutInflater
import android.view.View
@@ -15,7 +15,7 @@
import org.junit.runner.RunWith
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@RunWithLooper(setAsMainLooper = true)
class KeyguardStatusViewTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUnfoldTransitionTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUnfoldTransitionTest.kt
index 336183d..2e41246 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUnfoldTransitionTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUnfoldTransitionTest.kt
@@ -16,8 +16,9 @@
package com.android.keyguard
-import android.testing.AndroidTestingRunner
import android.view.View
+import android.view.ViewGroup
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.keyguard.ui.view.KeyguardRootView
@@ -43,7 +44,7 @@
* the set of ids, which also dictact which direction to move and when, via a filter fn.
*/
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class KeyguardUnfoldTransitionTest : SysuiTestCase() {
private val kosmos = Kosmos()
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index ee0cefb..075d8ae 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -108,10 +108,10 @@
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.text.TextUtils;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.dx.mockito.inline.extended.ExtendedMockito;
@@ -176,7 +176,7 @@
import java.util.concurrent.atomic.AtomicInteger;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper
public class KeyguardUpdateMonitorTest extends SysuiTestCase {
private static final String PKG_ALLOWING_FP_LISTEN_ON_OCCLUDING_ACTIVITY =
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUserSwitcherAnchorTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUserSwitcherAnchorTest.kt
index c674053..e7b42624 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUserSwitcherAnchorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUserSwitcherAnchorTest.kt
@@ -15,8 +15,8 @@
*/
package com.android.keyguard
-import android.testing.AndroidTestingRunner
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.res.R
import com.android.systemui.SysuiTestCase
@@ -25,7 +25,7 @@
import org.junit.Test
import org.junit.runner.RunWith
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
class KeyguardUserSwitcherAnchorTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/LegacyLockIconViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/LegacyLockIconViewControllerTest.java
index 255c7d9..c1ba39e 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/LegacyLockIconViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/LegacyLockIconViewControllerTest.java
@@ -32,12 +32,12 @@
import android.graphics.Point;
import android.hardware.biometrics.BiometricSourceType;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.util.Pair;
import android.view.HapticFeedbackConstants;
import android.view.View;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.biometrics.UdfpsController;
@@ -50,7 +50,7 @@
import org.junit.runner.RunWith;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper
public class LegacyLockIconViewControllerTest extends LegacyLockIconViewControllerBaseTest {
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/LegacyLockIconViewControllerWithCoroutinesTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/LegacyLockIconViewControllerWithCoroutinesTest.kt
index 9580139..2fd3cb0 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/LegacyLockIconViewControllerWithCoroutinesTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/LegacyLockIconViewControllerWithCoroutinesTest.kt
@@ -16,8 +16,8 @@
package com.android.keyguard
-import android.testing.AndroidTestingRunner
import android.view.View
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.keyguard.LockIconView.ICON_LOCK
import com.android.systemui.doze.util.getBurnInOffset
@@ -33,7 +33,7 @@
import org.mockito.Mockito.reset
import org.mockito.Mockito.verify
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
class LegacyLockIconViewControllerWithCoroutinesTest : LegacyLockIconViewControllerBaseTest() {
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/NumPadAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/NumPadAnimatorTest.kt
index 7c2550f..18976e1 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/NumPadAnimatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/NumPadAnimatorTest.kt
@@ -17,8 +17,8 @@
import android.graphics.drawable.Drawable
import android.graphics.drawable.GradientDrawable
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import org.junit.Before
@@ -32,7 +32,7 @@
import org.mockito.MockitoAnnotations
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@TestableLooper.RunWithLooper
class NumPadAnimatorTest : SysuiTestCase() {
@Mock lateinit var background: GradientDrawable
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/PinShapeHintingViewTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/PinShapeHintingViewTest.kt
index 835c9ff5..d8f2b10 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/PinShapeHintingViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/PinShapeHintingViewTest.kt
@@ -16,9 +16,9 @@
package com.android.keyguard
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.view.LayoutInflater
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.res.R
import com.android.systemui.SysuiTestCase
@@ -28,7 +28,7 @@
import org.junit.runner.RunWith
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@TestableLooper.RunWithLooper
class PinShapeHintingViewTest : SysuiTestCase() {
lateinit var underTest: PinShapeHintingView
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/PinShapeNonHintingViewTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/PinShapeNonHintingViewTest.kt
index d431731..447cf65 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/PinShapeNonHintingViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/PinShapeNonHintingViewTest.kt
@@ -16,9 +16,9 @@
package com.android.keyguard
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.view.LayoutInflater
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.res.R
import com.android.systemui.SysuiTestCase
@@ -28,7 +28,7 @@
import org.junit.runner.RunWith
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@TestableLooper.RunWithLooper
class PinShapeNonHintingViewTest : SysuiTestCase() {
lateinit var underTest: PinShapeNonHintingView
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/SplitShadeTransitionAdapterTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/SplitShadeTransitionAdapterTest.kt
index 9f9b9a4..c7d11ef 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/SplitShadeTransitionAdapterTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/SplitShadeTransitionAdapterTest.kt
@@ -16,10 +16,10 @@
package com.android.keyguard
import android.animation.Animator
-import android.testing.AndroidTestingRunner
import android.transition.TransitionValues
import android.view.View
import android.view.ViewGroup
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.keyguard.KeyguardStatusViewController.SplitShadeTransitionAdapter
import com.android.systemui.SysuiTestCase
@@ -32,7 +32,7 @@
import org.mockito.MockitoAnnotations
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class SplitShadeTransitionAdapterTest : SysuiTestCase() {
@Mock private lateinit var KeyguardClockSwitchController: KeyguardClockSwitchController
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/mediator/ScreenOnCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/mediator/ScreenOnCoordinatorTest.kt
index fb649c8..5247a89 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/mediator/ScreenOnCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/mediator/ScreenOnCoordinatorTest.kt
@@ -19,7 +19,7 @@
import android.os.Looper
import android.platform.test.flag.junit.SetFlagsRule
import android.platform.test.flag.junit.SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.Flags
import com.android.systemui.SysuiTestCase
@@ -43,7 +43,7 @@
import java.util.Optional
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class ScreenOnCoordinatorTest : SysuiTestCase() {
@Mock
diff --git a/packages/SystemUI/tests/src/com/android/systemui/BootCompleteCacheTest.kt b/packages/SystemUI/tests/src/com/android/systemui/BootCompleteCacheTest.kt
index 2551650..0a9ce68 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/BootCompleteCacheTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/BootCompleteCacheTest.kt
@@ -16,7 +16,7 @@
package com.android.systemui
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.dump.DumpManager
import org.junit.Assert.assertFalse
@@ -30,7 +30,7 @@
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
class BootCompleteCacheTest : SysuiTestCase() {
@@ -116,4 +116,4 @@
verify(bootCompleteListener, never()).onBootComplete()
}
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/CameraAvailabilityListenerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/CameraAvailabilityListenerTest.kt
index f776a63..a23e829 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/CameraAvailabilityListenerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/CameraAvailabilityListenerTest.kt
@@ -4,8 +4,8 @@
import android.graphics.Rect
import android.graphics.RectF
import android.hardware.camera2.CameraManager
-import android.testing.AndroidTestingRunner
import android.util.PathParser
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.res.R
import com.android.systemui.util.mockito.any
@@ -19,7 +19,7 @@
import org.junit.Test
import org.junit.runner.RunWith
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
class CameraAvailabilityListenerTest : SysuiTestCase() {
companion object {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/DependencyTest.java b/packages/SystemUI/tests/src/com/android/systemui/DependencyTest.java
index 2e04007..0068644 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/DependencyTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/DependencyTest.java
@@ -18,14 +18,17 @@
import android.os.Looper;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import org.junit.Assert;
import org.junit.Test;
+import org.junit.runner.RunWith;
import java.util.concurrent.ExecutionException;
@SmallTest
+@RunWith(AndroidJUnit4.class)
public class DependencyTest extends SysuiTestCase {
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/DisplayCutoutBaseViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/DisplayCutoutBaseViewTest.kt
index 5886206..091072f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/DisplayCutoutBaseViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/DisplayCutoutBaseViewTest.kt
@@ -23,11 +23,11 @@
import android.graphics.Rect
import android.graphics.RectF
import android.graphics.Region
-import android.testing.AndroidTestingRunner
import android.view.Display
import android.view.DisplayCutout
import android.view.DisplayInfo
import android.view.View
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.dx.mockito.inline.extended.ExtendedMockito.never
import com.android.internal.R
@@ -42,7 +42,7 @@
import org.mockito.MockitoAnnotations
import org.mockito.Mockito.`when` as whenever
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
class DisplayCutoutBaseViewTest : SysuiTestCase() {
@@ -183,4 +183,4 @@
return@then true
}
}
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/FaceScanningProviderFactoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/FaceScanningProviderFactoryTest.kt
index 46936d6..bc12aaa 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/FaceScanningProviderFactoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/FaceScanningProviderFactoryTest.kt
@@ -16,11 +16,11 @@
import android.graphics.Point
import android.hardware.display.DisplayManagerGlobal
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
import android.view.Display
import android.view.DisplayAdjustments
import android.view.DisplayInfo
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.internal.R
import com.android.keyguard.KeyguardUpdateMonitor
@@ -42,7 +42,7 @@
import org.mockito.MockitoAnnotations
@RunWithLooper
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
class FaceScanningProviderFactoryTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorHwcLayerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorHwcLayerTest.kt
index d500b5a..fb60ba3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorHwcLayerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorHwcLayerTest.kt
@@ -22,11 +22,11 @@
import android.graphics.Rect
import android.graphics.RectF
import android.hardware.graphics.common.DisplayDecorationSupport
-import android.testing.AndroidTestingRunner
import android.view.Display
import android.view.DisplayCutout
import android.view.DisplayInfo
import android.view.View
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.internal.R
import com.android.systemui.util.mockito.eq
@@ -39,7 +39,7 @@
import org.mockito.MockitoAnnotations
import org.mockito.Mockito.`when` as whenever
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
class ScreenDecorHwcLayerTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
index 54a14a2..997f8a8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
@@ -61,7 +61,6 @@
import android.hardware.display.DisplayManager;
import android.hardware.graphics.common.DisplayDecorationSupport;
import android.os.Handler;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
import android.util.PathParser;
@@ -78,6 +77,7 @@
import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.keyguard.KeyguardUpdateMonitor;
@@ -121,7 +121,7 @@
import java.util.List;
@RunWithLooper
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@SmallTest
public class ScreenDecorationsTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/SystemActionsTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/SystemActionsTest.java
index f46b2f9..53b98d5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/SystemActionsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/SystemActionsTest.java
@@ -26,10 +26,14 @@
import android.hardware.input.InputManager;
import android.os.RemoteException;
+import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.telecom.TelecomManager;
import android.telephony.TelephonyManager;
import android.testing.TestableLooper;
import android.view.KeyEvent;
+import android.view.accessibility.Flags;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
@@ -44,6 +48,7 @@
import com.android.systemui.statusbar.policy.KeyguardStateController;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -77,6 +82,9 @@
private SystemActions mSystemActions;
+ @Rule
+ public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
+
@Before
public void setUp() throws RemoteException {
MockitoAnnotations.initMocks(this);
@@ -131,4 +139,40 @@
verify(mTelecomManager).endCall();
}
+
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_GLOBAL_ACTION_MENU)
+ public void handleMenu_injectsKeyEvents() {
+ final List<KeyEvent> keyEvents = new ArrayList<>();
+ doAnswer(invocation -> {
+ keyEvents.add(new KeyEvent(invocation.getArgument(0)));
+ return null;
+ }).when(mInputManager).injectInputEvent(any(), anyInt());
+
+ mSystemActions.handleMenu();
+
+ assertThat(keyEvents.size()).isEqualTo(2);
+ assertThat(keyEvents.get(0).getKeyCode()).isEqualTo(KeyEvent.KEYCODE_MENU);
+ assertThat(keyEvents.get(0).getAction()).isEqualTo(KeyEvent.ACTION_DOWN);
+ assertThat(keyEvents.get(1).getKeyCode()).isEqualTo(KeyEvent.KEYCODE_MENU);
+ assertThat(keyEvents.get(1).getAction()).isEqualTo(KeyEvent.ACTION_UP);
+ }
+
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_GLOBAL_ACTION_MEDIA_PLAY_PAUSE)
+ public void handleMediaPlayPause_injectsKeyEvents() {
+ final List<KeyEvent> keyEvents = new ArrayList<>();
+ doAnswer(invocation -> {
+ keyEvents.add(new KeyEvent(invocation.getArgument(0)));
+ return null;
+ }).when(mInputManager).injectInputEvent(any(), anyInt());
+
+ mSystemActions.handleMediaPlayPause();
+
+ assertThat(keyEvents.size()).isEqualTo(2);
+ assertThat(keyEvents.get(0).getKeyCode()).isEqualTo(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE);
+ assertThat(keyEvents.get(0).getAction()).isEqualTo(KeyEvent.ACTION_DOWN);
+ assertThat(keyEvents.get(1).getKeyCode()).isEqualTo(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE);
+ assertThat(keyEvents.get(1).getAction()).isEqualTo(KeyEvent.ACTION_UP);
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java
index 38095c8..c30bedd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java
@@ -258,8 +258,9 @@
setupEnabledAccessibilityServiceList();
mMenuViewLayer.mDismissMenuAction.run();
- final String value = Settings.Secure.getString(mSpyContext.getContentResolver(),
- Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
+ final String value = Settings.Secure.getStringForUser(mSpyContext.getContentResolver(),
+ Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
+ mSecureSettings.getRealUserHandle(UserHandle.USER_CURRENT));
assertThat(value).isEqualTo("");
}
@@ -274,8 +275,9 @@
ShortcutConstants.UserShortcutType.HARDWARE)).thenReturn(stubShortcutTargets);
mMenuViewLayer.mDismissMenuAction.run();
- final String value = Settings.Secure.getString(mSpyContext.getContentResolver(),
- Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
+ final String value = Settings.Secure.getStringForUser(mSpyContext.getContentResolver(),
+ Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
+ mSecureSettings.getRealUserHandle(UserHandle.USER_CURRENT));
assertThat(value).isEqualTo(TEST_SELECT_TO_SPEAK_COMPONENT_NAME.flattenToString());
}
@@ -445,9 +447,11 @@
}
private void setupEnabledAccessibilityServiceList() {
- Settings.Secure.putString(mSpyContext.getContentResolver(),
+ Settings.Secure.putStringForUser(mSpyContext.getContentResolver(),
Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
- TEST_SELECT_TO_SPEAK_COMPONENT_NAME.flattenToString());
+ TEST_SELECT_TO_SPEAK_COMPONENT_NAME.flattenToString(),
+ mSecureSettings.getRealUserHandle(UserHandle.USER_CURRENT)
+ );
final ResolveInfo resolveInfo = new ResolveInfo();
final ServiceInfo serviceInfo = new ServiceInfo();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesCheckerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesCheckerTest.java
index 51f6cdb..7320bbf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesCheckerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesCheckerTest.java
@@ -22,9 +22,9 @@
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
@@ -44,7 +44,7 @@
import java.util.ArrayList;
import java.util.List;
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
@SmallTest
public class HearingDevicesCheckerTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/battery/AccessorizedBatteryDrawableTest.kt b/packages/SystemUI/tests/src/com/android/systemui/battery/AccessorizedBatteryDrawableTest.kt
index 982f033..99d3600 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/battery/AccessorizedBatteryDrawableTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/battery/AccessorizedBatteryDrawableTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.battery
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.battery.BatterySpecs.BATTERY_HEIGHT
@@ -24,8 +25,10 @@
import com.android.systemui.battery.BatterySpecs.BATTERY_WIDTH_WITH_SHIELD
import com.google.common.truth.Truth.assertThat
import org.junit.Test
+import org.junit.runner.RunWith
@SmallTest
+@RunWith(AndroidJUnit4::class)
class AccessorizedBatteryDrawableTest : SysuiTestCase() {
@Test
fun intrinsicSize_shieldFalse_isBatterySize() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/battery/BatteryMeterViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/battery/BatteryMeterViewControllerTest.java
index 14eff2f..d940fc9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/battery/BatteryMeterViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/battery/BatteryMeterViewControllerTest.java
@@ -31,6 +31,7 @@
import android.os.Handler;
import android.provider.Settings;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -44,10 +45,12 @@
import org.junit.Before;
import org.junit.Test;
+import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@SmallTest
+@RunWith(AndroidJUnit4.class)
public class BatteryMeterViewControllerTest extends SysuiTestCase {
@Mock
private BatteryMeterView mBatteryMeterView;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/battery/BatterySpecsTest.kt b/packages/SystemUI/tests/src/com/android/systemui/battery/BatterySpecsTest.kt
index 39cb047..cac0b66 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/battery/BatterySpecsTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/battery/BatterySpecsTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.battery
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.battery.BatterySpecs.BATTERY_HEIGHT
@@ -24,8 +25,10 @@
import com.android.systemui.battery.BatterySpecs.BATTERY_WIDTH_WITH_SHIELD
import com.google.common.truth.Truth.assertThat
import org.junit.Test
+import org.junit.runner.RunWith
@SmallTest
+@RunWith(AndroidJUnit4::class)
class BatterySpecsTest : SysuiTestCase() {
@Test
fun getFullBatteryHeight_shieldFalse_returnsMainHeight() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardImageLoaderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardImageLoaderTest.kt
index 21516d49..791f1f2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardImageLoaderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardImageLoaderTest.kt
@@ -18,6 +18,7 @@
import android.content.ContentResolver
import android.content.Context
import android.net.Uri
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.util.mockito.whenever
@@ -29,6 +30,7 @@
import org.junit.Assert.assertNull
import org.junit.Before
import org.junit.Test
+import org.junit.runner.RunWith
import org.mockito.ArgumentMatchers.any
import org.mockito.ArgumentMatchers.eq
import org.mockito.Mock
@@ -37,6 +39,7 @@
@SmallTest
@OptIn(ExperimentalCoroutinesApi::class)
+@RunWith(AndroidJUnit4::class)
class ClipboardImageLoaderTest : SysuiTestCase() {
@Mock private lateinit var mockContext: Context
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/TemperatureControlBehaviorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/TemperatureControlBehaviorTest.kt
index ac1f90c..b3f4588 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/TemperatureControlBehaviorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/TemperatureControlBehaviorTest.kt
@@ -10,6 +10,7 @@
import android.service.controls.templates.ThumbnailTemplate
import android.view.LayoutInflater
import android.view.ViewGroup
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.res.R
import com.android.systemui.SysuiTestCase
@@ -20,10 +21,12 @@
import com.android.systemui.util.time.FakeSystemClock
import org.junit.Before
import org.junit.Test
+import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.MockitoAnnotations
@SmallTest
+@RunWith(AndroidJUnit4::class)
class TemperatureControlBehaviorTest : SysuiTestCase() {
@Mock lateinit var controlsMetricsLogger: ControlsMetricsLogger
diff --git a/packages/SystemUI/tests/src/com/android/systemui/deviceentry/shared/FaceAuthReasonTest.kt b/packages/SystemUI/tests/src/com/android/systemui/deviceentry/shared/FaceAuthReasonTest.kt
index ef89752..82ad30e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/deviceentry/shared/FaceAuthReasonTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/deviceentry/shared/FaceAuthReasonTest.kt
@@ -16,13 +16,16 @@
package com.android.systemui.deviceentry.shared
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import junit.framework.Assert
import kotlin.reflect.full.declaredMembers
import org.junit.Test
+import org.junit.runner.RunWith
@SmallTest
+@RunWith(AndroidJUnit4::class)
class FaceAuthReasonTest : SysuiTestCase() {
@Test
fun testApiReasonToUiEvent_forAllReasons_isNotNull() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DisplayMetricsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DisplayMetricsRepositoryTest.kt
index dd741b4..d79db5c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DisplayMetricsRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DisplayMetricsRepositoryTest.kt
@@ -19,6 +19,7 @@
import android.content.Context
import android.util.DisplayMetrics
import android.view.Display
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.log.LogBuffer
@@ -33,9 +34,11 @@
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
+import org.junit.runner.RunWith
@SmallTest
@OptIn(ExperimentalCoroutinesApi::class)
+@RunWith(AndroidJUnit4::class)
class DisplayMetricsRepositoryTest : SysuiTestCase() {
private lateinit var underTest: DisplayMetricsRepository
diff --git a/packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DisplayRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DisplayRepositoryTest.kt
index 01868ae..1c327af 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DisplayRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DisplayRepositoryTest.kt
@@ -126,6 +126,7 @@
// All subscribers are done, unregister should have been called.
verify(displayManager).unregisterDisplayListener(any())
}
+
@Test
fun onDisplayAdded_propagated() =
testScope.runTest {
@@ -457,6 +458,16 @@
assertThat(defaultDisplayOff).isFalse()
}
+ @Test
+ fun displayFlow_startsWithDefaultDisplayBeforeAnyEvent() =
+ testScope.runTest {
+ setDisplays(Display.DEFAULT_DISPLAY)
+
+ val value by latestDisplayFlowValue()
+
+ assertThat(value?.ids()).containsExactly(Display.DEFAULT_DISPLAY)
+ }
+
private fun Iterable<Display>.ids(): List<Int> = map { it.displayId }
// Wrapper to capture the displayListener.
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenStatePreventingAdapterTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenStatePreventingAdapterTest.java
index a7d7b93..419f7ed 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenStatePreventingAdapterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenStatePreventingAdapterTest.java
@@ -24,6 +24,7 @@
import android.view.Display;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -33,10 +34,12 @@
import org.junit.Before;
import org.junit.Test;
+import org.junit.runner.RunWith;
import java.util.concurrent.Executor;
@SmallTest
+@RunWith(AndroidJUnit4.class)
public class DozeScreenStatePreventingAdapterTest extends SysuiTestCase {
private Executor mExecutor;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSuspendScreenStatePreventingAdapterTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSuspendScreenStatePreventingAdapterTest.java
index 240d2d7..5a89710 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSuspendScreenStatePreventingAdapterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSuspendScreenStatePreventingAdapterTest.java
@@ -24,6 +24,7 @@
import android.view.Display;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -33,10 +34,12 @@
import org.junit.Before;
import org.junit.Test;
+import org.junit.runner.RunWith;
import java.util.concurrent.Executor;
@SmallTest
+@RunWith(AndroidJUnit4.class)
public class DozeSuspendScreenStatePreventingAdapterTest extends SysuiTestCase {
private Executor mExecutor;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dump/DumpHandlerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/dump/DumpHandlerTest.kt
index 840eb46..5976292 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dump/DumpHandlerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/dump/DumpHandlerTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.dump
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.CoreStartable
import com.android.systemui.Dumpable
@@ -28,6 +29,7 @@
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
+import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.Mockito.anyInt
import org.mockito.Mockito.never
@@ -39,6 +41,7 @@
import javax.inject.Provider
@SmallTest
+@RunWith(AndroidJUnit4::class)
class DumpHandlerTest : SysuiTestCase() {
private lateinit var dumpHandler: DumpHandler
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dump/DumpManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/dump/DumpManagerTest.kt
index 6d5226f..f331060 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dump/DumpManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/dump/DumpManagerTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.dump
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.Dumpable
import com.android.systemui.SysuiTestCase
@@ -25,10 +26,12 @@
import org.junit.Assert.assertThrows
import org.junit.Before
import org.junit.Test
+import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.MockitoAnnotations
@SmallTest
+@RunWith(AndroidJUnit4::class)
class DumpManagerTest : SysuiTestCase() {
@Mock private lateinit var dumpable1: Dumpable
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dump/DumpsysTableLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/dump/DumpsysTableLoggerTest.kt
index 1d2afe4..d09928b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dump/DumpsysTableLoggerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/dump/DumpsysTableLoggerTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.dump
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
@@ -24,11 +25,13 @@
import org.junit.Assert.assertEquals
import org.junit.Before
import org.junit.Test
+import org.junit.runner.RunWith
import java.io.PrintWriter
import java.io.StringWriter
@SmallTest
+@RunWith(AndroidJUnit4::class)
class DumpsysTableLoggerTest : SysuiTestCase() {
private val logger = DumpsysTableLogger(
TEST_SECTION_NAME,
@@ -143,4 +146,4 @@
List(TEST_COLUMNS.size) { col ->
"data$col$row"
}
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dump/LogBufferFreezerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/dump/LogBufferFreezerTest.kt
index 3b4888f..0cd2b9f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dump/LogBufferFreezerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/dump/LogBufferFreezerTest.kt
@@ -19,6 +19,7 @@
import android.content.BroadcastReceiver
import android.content.IntentFilter
import android.os.UserHandle
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.broadcast.BroadcastDispatcher
@@ -30,6 +31,7 @@
import com.android.systemui.util.time.FakeSystemClock
import org.junit.Before
import org.junit.Test
+import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
import org.mockito.Captor
import org.mockito.Mock
@@ -40,6 +42,7 @@
import org.mockito.MockitoAnnotations
@SmallTest
+@RunWith(AndroidJUnit4::class)
class LogBufferFreezerTest : SysuiTestCase() {
lateinit var freezer: LogBufferFreezer
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dump/LogEulogizerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/dump/LogEulogizerTest.kt
index 3ff7202..ae6b337 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dump/LogEulogizerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/dump/LogEulogizerTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.dump
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.dump.DumpHandler.Companion.dump
@@ -40,6 +41,7 @@
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Test
+import org.junit.runner.RunWith
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.Mock
import org.mockito.Mockito
@@ -48,6 +50,7 @@
import org.mockito.MockitoAnnotations
@SmallTest
+@RunWith(AndroidJUnit4::class)
class LogEulogizerTest : SysuiTestCase() {
lateinit var eulogizer: LogBufferEulogizer
diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/ConditionalRestarterTest.kt b/packages/SystemUI/tests/src/com/android/systemui/flags/ConditionalRestarterTest.kt
index 52c6e22..9f238e6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/flags/ConditionalRestarterTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/flags/ConditionalRestarterTest.kt
@@ -15,6 +15,7 @@
*/
package com.android.systemui.flags
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.util.mockito.any
@@ -26,6 +27,7 @@
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
+import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
@@ -35,6 +37,7 @@
* Be careful with the {FeatureFlagsReleaseRestarter} in this test. It has a call to System.exit()!
*/
@SmallTest
+@RunWith(AndroidJUnit4::class)
class ConditionalRestarterTest : SysuiTestCase() {
private lateinit var restarter: ConditionalRestarter
diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsClassicDebugTest.kt b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsClassicDebugTest.kt
index dbe59e6..a1fe0f0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsClassicDebugTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsClassicDebugTest.kt
@@ -23,6 +23,7 @@
import android.content.res.Resources.NotFoundException
import android.platform.test.annotations.DisableFlags
import android.platform.test.annotations.EnableFlags
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.Flags.FLAG_SYSUI_TEAMFOOD
import com.android.systemui.SysuiTestCase
@@ -39,6 +40,7 @@
import org.junit.Assert
import org.junit.Before
import org.junit.Test
+import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.Mockito.anyBoolean
import org.mockito.Mockito.anyString
@@ -55,6 +57,7 @@
* the default.
*/
@SmallTest
+@RunWith(AndroidJUnit4::class)
class FeatureFlagsClassicDebugTest : SysuiTestCase() {
private lateinit var mFeatureFlagsClassicDebug: FeatureFlagsClassicDebug
diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsClassicReleaseTest.kt b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsClassicReleaseTest.kt
index 943e212..ad8bedb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsClassicReleaseTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsClassicReleaseTest.kt
@@ -17,12 +17,14 @@
import android.content.pm.PackageManager.NameNotFoundException
import android.content.res.Resources
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.google.common.truth.Truth.assertThat
import org.junit.Assert.assertThrows
import org.junit.Before
import org.junit.Test
+import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.Mockito
import org.mockito.Mockito.never
@@ -34,6 +36,7 @@
* overriding, and should never return any value other than the one provided as the default.
*/
@SmallTest
+@RunWith(AndroidJUnit4::class)
class FeatureFlagsClassicReleaseTest : SysuiTestCase() {
private lateinit var mFeatureFlagsClassicRelease: FeatureFlagsClassicRelease
diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/FlagCommandTest.kt b/packages/SystemUI/tests/src/com/android/systemui/flags/FlagCommandTest.kt
index d500dd2..dd56fa6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/flags/FlagCommandTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/flags/FlagCommandTest.kt
@@ -16,18 +16,21 @@
package com.android.systemui.flags
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.util.mockito.any
import java.io.PrintWriter
import org.junit.Before
import org.junit.Test
+import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.Mockito
import org.mockito.Mockito.`when` as whenever
import org.mockito.MockitoAnnotations
@SmallTest
+@RunWith(AndroidJUnit4::class)
class FlagCommandTest : SysuiTestCase() {
@Mock private lateinit var featureFlags: FeatureFlagsClassicDebug
diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/FlagManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/flags/FlagManagerTest.kt
index 5e87a6f..593de37 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/flags/FlagManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/flags/FlagManagerTest.kt
@@ -19,6 +19,7 @@
import android.database.ContentObserver
import android.net.Uri
import android.os.Handler
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.util.mockito.any
@@ -30,6 +31,7 @@
import org.junit.Assert.assertThrows
import org.junit.Before
import org.junit.Test
+import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
@@ -42,6 +44,7 @@
* overriding, and should never return any value other than the one provided as the default.
*/
@SmallTest
+@RunWith(AndroidJUnit4::class)
class FlagManagerTest : SysuiTestCase() {
private lateinit var mFlagManager: FlagManager
diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/NotOccludedConditionTest.kt b/packages/SystemUI/tests/src/com/android/systemui/flags/NotOccludedConditionTest.kt
index 755cc46..46b4c4b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/flags/NotOccludedConditionTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/flags/NotOccludedConditionTest.kt
@@ -15,6 +15,7 @@
*/
package com.android.systemui.flags
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
@@ -30,6 +31,7 @@
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
+import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.Mockito.`when` as whenever
import org.mockito.MockitoAnnotations
@@ -39,6 +41,7 @@
*/
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
+@RunWith(AndroidJUnit4::class)
class NotOccludedConditionTest : SysuiTestCase() {
private lateinit var condition: NotOccludedCondition
diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/PluggedInConditionTest.kt b/packages/SystemUI/tests/src/com/android/systemui/flags/PluggedInConditionTest.kt
index 0fdda08..0f727cb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/flags/PluggedInConditionTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/flags/PluggedInConditionTest.kt
@@ -15,6 +15,7 @@
*/
package com.android.systemui.flags
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
@@ -26,6 +27,7 @@
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
+import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
import org.mockito.Mock
import org.mockito.Mockito.verify
@@ -36,6 +38,7 @@
* Be careful with the {FeatureFlagsReleaseRestarter} in this test. It has a call to System.exit()!
*/
@SmallTest
+@RunWith(AndroidJUnit4::class)
class PluggedInConditionTest : SysuiTestCase() {
private lateinit var condition: PluggedInCondition
diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/RestartDozeListenerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/flags/RestartDozeListenerTest.kt
index 3c965ce..1ab945a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/flags/RestartDozeListenerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/flags/RestartDozeListenerTest.kt
@@ -17,6 +17,7 @@
package com.android.systemui.flags
import android.os.PowerManager
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.plugins.statusbar.StatusBarStateController
@@ -27,6 +28,7 @@
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
+import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.ArgumentMatchers.anyString
@@ -37,6 +39,7 @@
import org.mockito.MockitoAnnotations
@SmallTest
+@RunWith(AndroidJUnit4::class)
class RestartDozeListenerTest : SysuiTestCase() {
lateinit var restartDozeListener: RestartDozeListener
diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/ScreenIdleConditionTest.kt b/packages/SystemUI/tests/src/com/android/systemui/flags/ScreenIdleConditionTest.kt
index 0116e53..df03882 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/flags/ScreenIdleConditionTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/flags/ScreenIdleConditionTest.kt
@@ -15,6 +15,7 @@
*/
package com.android.systemui.flags
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
@@ -27,6 +28,7 @@
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
+import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.Mockito.`when` as whenever
import org.mockito.MockitoAnnotations
@@ -35,6 +37,7 @@
* Be careful with the {FeatureFlagsReleaseRestarter} in this test. It has a call to System.exit()!
*/
@SmallTest
+@RunWith(AndroidJUnit4::class)
class ScreenIdleConditionTest : SysuiTestCase() {
private lateinit var condition: ScreenIdleCondition
diff --git a/packages/SystemUI/tests/src/com/android/systemui/fragments/FragmentServiceTest.kt b/packages/SystemUI/tests/src/com/android/systemui/fragments/FragmentServiceTest.kt
index 8a29217..008c68d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/fragments/FragmentServiceTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/fragments/FragmentServiceTest.kt
@@ -2,6 +2,7 @@
import android.app.Fragment
import android.os.Looper
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.dump.DumpManager
@@ -9,8 +10,10 @@
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
+import org.junit.runner.RunWith
@SmallTest
+@RunWith(AndroidJUnit4::class)
class FragmentServiceTest : SysuiTestCase() {
private val fragmentHostManagerFactory: FragmentHostManager.Factory = mock()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsImeTest.java b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsImeTest.java
index 7f55d38..dc019b6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsImeTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsImeTest.java
@@ -37,6 +37,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.FlakyTest;
import androidx.test.filters.LargeTest;
import androidx.test.platform.app.InstrumentationRegistry;
@@ -48,6 +49,7 @@
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
+import org.junit.runner.RunWith;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
@@ -55,6 +57,7 @@
@LargeTest
@FlakyTest(bugId = 176891566)
+@RunWith(AndroidJUnit4.class)
public class GlobalActionsImeTest extends SysuiTestCase {
@Rule
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyboard/docking/ui/viewmodel/KeyboardDockingIndicationViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyboard/docking/ui/viewmodel/KeyboardDockingIndicationViewModelTest.kt
index 3a86868..2735d2f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyboard/docking/ui/viewmodel/KeyboardDockingIndicationViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyboard/docking/ui/viewmodel/KeyboardDockingIndicationViewModelTest.kt
@@ -20,6 +20,7 @@
import android.view.WindowInsets
import android.view.WindowManager
import android.view.WindowMetrics
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository
@@ -33,14 +34,13 @@
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
import org.mockito.Mockito.spy
import org.mockito.MockitoAnnotations
import org.mockito.kotlin.doReturn
import org.mockito.kotlin.whenever
@SmallTest
-@RunWith(JUnit4::class)
+@RunWith(AndroidJUnit4::class)
class KeyboardDockingIndicationViewModelTest : SysuiTestCase() {
private val testScope = TestScope(StandardTestDispatcher())
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerViewBinderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerViewBinderTest.kt
new file mode 100644
index 0000000..c4eabd8
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerViewBinderTest.kt
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyguard.ui.binder
+
+import android.platform.test.annotations.EnableFlags
+import android.testing.TestableLooper
+import android.view.View
+import android.view.layoutInflater
+import android.view.mockedLayoutInflater
+import android.view.windowManager
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.Flags.FLAG_DEVICE_ENTRY_UDFPS_REFACTOR
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.bouncer.domain.interactor.givenCanShowAlternateBouncer
+import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.res.R
+import com.android.systemui.testKosmos
+import com.android.systemui.util.mockito.eq
+import com.android.systemui.util.mockito.whenever
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.Mockito.any
+import org.mockito.Mockito.anyBoolean
+import org.mockito.Mockito.atLeastOnce
+import org.mockito.Mockito.never
+import org.mockito.Mockito.spy
+import org.mockito.Mockito.verify
+import org.mockito.kotlin.isNull
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+class AlternateBouncerViewBinderTest : SysuiTestCase() {
+ private val kosmos = testKosmos()
+ private val testScope = kosmos.testScope
+
+ private val mockedAltBouncerView =
+ spy(kosmos.layoutInflater.inflate(R.layout.alternate_bouncer, null, false))
+
+ @Before
+ fun setup() {
+ whenever(
+ kosmos.mockedLayoutInflater.inflate(
+ eq(R.layout.alternate_bouncer),
+ isNull(),
+ anyBoolean()
+ )
+ )
+ .thenReturn(mockedAltBouncerView)
+ kosmos.alternateBouncerViewBinder.start()
+ }
+
+ @Test
+ @EnableFlags(FLAG_DEVICE_ENTRY_UDFPS_REFACTOR)
+ fun addViewToWindowManager() {
+ testScope.runTest {
+ kosmos.givenCanShowAlternateBouncer()
+ kosmos.fakeKeyguardTransitionRepository.sendTransitionSteps(
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.ALTERNATE_BOUNCER,
+ testScope,
+ )
+ verify(kosmos.windowManager).addView(any(), any())
+ }
+ }
+
+ @Test
+ @EnableFlags(FLAG_DEVICE_ENTRY_UDFPS_REFACTOR)
+ fun viewRemovedImmediatelyIfAlreadyAttachedToWindow() {
+ testScope.runTest {
+ kosmos.givenCanShowAlternateBouncer()
+ kosmos.fakeKeyguardTransitionRepository.sendTransitionSteps(
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.ALTERNATE_BOUNCER,
+ testScope,
+ )
+ verify(kosmos.windowManager).addView(any(), any())
+ whenever(mockedAltBouncerView.isAttachedToWindow).thenReturn(true)
+
+ kosmos.fakeKeyguardTransitionRepository.sendTransitionSteps(
+ from = KeyguardState.ALTERNATE_BOUNCER,
+ to = KeyguardState.LOCKSCREEN,
+ testScope,
+ )
+ verify(kosmos.windowManager).removeView(any())
+ }
+ }
+
+ @Test
+ @EnableFlags(FLAG_DEVICE_ENTRY_UDFPS_REFACTOR)
+ fun viewNotRemovedUntilAttachedToWindow() {
+ testScope.runTest {
+ kosmos.givenCanShowAlternateBouncer()
+ kosmos.fakeKeyguardTransitionRepository.sendTransitionSteps(
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.ALTERNATE_BOUNCER,
+ testScope,
+ )
+ verify(kosmos.windowManager).addView(any(), any())
+
+ kosmos.fakeKeyguardTransitionRepository.sendTransitionSteps(
+ from = KeyguardState.ALTERNATE_BOUNCER,
+ to = KeyguardState.LOCKSCREEN,
+ testScope,
+ )
+
+ verify(kosmos.windowManager, never()).removeView(any())
+ givenAltBouncerViewAttachedToWindow()
+ verify(kosmos.windowManager).removeView(any())
+ }
+ }
+
+ private fun givenAltBouncerViewAttachedToWindow() {
+ val attachStateChangeListenerCaptor =
+ ArgumentCaptor.forClass(View.OnAttachStateChangeListener::class.java)
+ verify(mockedAltBouncerView, atLeastOnce())
+ .addOnAttachStateChangeListener(attachStateChangeListenerCaptor.capture())
+ attachStateChangeListenerCaptor.allValues.onEach {
+ it.onViewAttachedToWindow(mockedAltBouncerView)
+ }
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/KeyguardSurfaceBehindParamsApplierTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/KeyguardSurfaceBehindParamsApplierTest.kt
index 7787a7f..9055495 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/KeyguardSurfaceBehindParamsApplierTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/KeyguardSurfaceBehindParamsApplierTest.kt
@@ -18,6 +18,7 @@
import android.testing.TestableLooper.RunWithLooper
import android.view.RemoteAnimationTarget
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.keyguard.KeyguardViewController
import com.android.systemui.SysuiTestCase
@@ -34,6 +35,7 @@
import org.junit.Before
import org.junit.Rule
import org.junit.Test
+import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.Mockito.anyBoolean
import org.mockito.Mockito.doAnswer
@@ -42,6 +44,7 @@
@SmallTest
@RunWithLooper(setAsMainLooper = true)
@kotlinx.coroutines.ExperimentalCoroutinesApi
+@RunWith(AndroidJUnit4::class)
class KeyguardSurfaceBehindParamsApplierTest : SysuiTestCase() {
@get:Rule val animatorTestRule = AnimatorTestRule(this)
@@ -155,4 +158,4 @@
// Releasing the surface should immediately cancel animators.
assertFalse(checkNotNull(isAnimatingSurface))
}
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/log/echo/LogcatEchoSettingsFormatTest.kt b/packages/SystemUI/tests/src/com/android/systemui/log/echo/LogcatEchoSettingsFormatTest.kt
index 02c9deb..aa4a6d1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/log/echo/LogcatEchoSettingsFormatTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/log/echo/LogcatEchoSettingsFormatTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.log.echo
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.log.core.LogLevel
@@ -24,8 +25,10 @@
import com.android.systemui.log.echo.EchoOverrideType.TAG
import kotlin.test.assertEquals
import org.junit.Test
+import org.junit.runner.RunWith
@SmallTest
+@RunWith(AndroidJUnit4::class)
class LogcatEchoSettingsFormatTest : SysuiTestCase() {
private val format = LogcatEchoSettingFormat()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/log/echo/LogcatEchoTrackerDebugTest.kt b/packages/SystemUI/tests/src/com/android/systemui/log/echo/LogcatEchoTrackerDebugTest.kt
index 7967134..a5f50af 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/log/echo/LogcatEchoTrackerDebugTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/log/echo/LogcatEchoTrackerDebugTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.log.echo
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.log.core.LogLevel.DEBUG
@@ -39,11 +40,13 @@
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Test
+import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.MockitoAnnotations
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
+@RunWith(AndroidJUnit4::class)
class LogcatEchoTrackerDebugTest : SysuiTestCase() {
private val dispatcher = StandardTestDispatcher()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/log/table/LogDiffsForTableTest.kt b/packages/SystemUI/tests/src/com/android/systemui/log/table/LogDiffsForTableTest.kt
index 1d182cf..e55cb12 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/log/table/LogDiffsForTableTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/log/table/LogDiffsForTableTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.log.table
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.log.table.TableChange.Companion.IS_INITIAL_PREFIX
@@ -35,9 +36,11 @@
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
+import org.junit.runner.RunWith
@SmallTest
@OptIn(ExperimentalCoroutinesApi::class)
+@RunWith(AndroidJUnit4::class)
class LogDiffsForTableTest : SysuiTestCase() {
private val testDispatcher = UnconfinedTestDispatcher()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/log/table/TableChangeTest.kt b/packages/SystemUI/tests/src/com/android/systemui/log/table/TableChangeTest.kt
index 43e430f..8d60811 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/log/table/TableChangeTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/log/table/TableChangeTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.log.table
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.log.table.TableChange.Companion.IS_INITIAL_PREFIX
@@ -23,8 +24,10 @@
import com.google.common.truth.Truth.assertThat
import junit.framework.Assert.assertTrue
import org.junit.Test
+import org.junit.runner.RunWith
@SmallTest
+@RunWith(AndroidJUnit4::class)
class TableChangeTest : SysuiTestCase() {
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/log/table/TableLogBufferFactoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/log/table/TableLogBufferFactoryTest.kt
index 8ba7643..8c62bc2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/log/table/TableLogBufferFactoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/log/table/TableLogBufferFactoryTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.log.table
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.dump.DumpManager
@@ -26,9 +27,11 @@
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.UnconfinedTestDispatcher
import org.junit.Test
+import org.junit.runner.RunWith
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
+@RunWith(AndroidJUnit4::class)
class TableLogBufferFactoryTest : SysuiTestCase() {
private val dumpManager: DumpManager = mock()
private val systemClock = FakeSystemClock()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/log/table/TableLogBufferTest.kt b/packages/SystemUI/tests/src/com/android/systemui/log/table/TableLogBufferTest.kt
index 5c9a003..ace562b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/log/table/TableLogBufferTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/log/table/TableLogBufferTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.log.table
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.log.LogcatEchoTracker
@@ -35,9 +36,11 @@
import kotlinx.coroutines.test.UnconfinedTestDispatcher
import org.junit.Before
import org.junit.Test
+import org.junit.runner.RunWith
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
+@RunWith(AndroidJUnit4::class)
class TableLogBufferTest : SysuiTestCase() {
private lateinit var underTest: TableLogBuffer
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDataCombineLatestTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDataCombineLatestTest.java
index 544350c..1d4b090 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDataCombineLatestTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDataCombineLatestTest.java
@@ -79,7 +79,7 @@
USER_ID, true, APP, null, ARTIST, TITLE, null,
new ArrayList<>(), new ArrayList<>(), null, PACKAGE, null, null, null, true, null,
MediaData.PLAYBACK_LOCAL, false, KEY, false, false, false, 0L, 0L,
- InstanceId.fakeInstanceId(-1), -1, false, null);
+ InstanceId.fakeInstanceId(-1), -1, false, null, -1, false);
mDeviceData = new MediaDeviceData(true, null, DEVICE_NAME, null, false);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDataFilterImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDataFilterImplTest.kt
index 4da56b5..c974e0d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDataFilterImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDataFilterImplTest.kt
@@ -740,11 +740,8 @@
// WHEN we have media that was recently played, but not currently active
val dataCurrent = dataMain.copy(active = false, lastActive = clock.elapsedRealtime())
- val controlCommonModel =
- MediaCommonModel.MediaControl(
- MediaDataLoadingModel.Loaded(dataMain.instanceId),
- true
- )
+ val mediaLoadingModel = MediaDataLoadingModel.Loaded(dataMain.instanceId)
+ var controlCommonModel = MediaCommonModel.MediaControl(mediaLoadingModel, true)
mediaDataFilter.onMediaDataLoaded(KEY, null, dataCurrent)
repository.setOrderedMedia()
assertThat(currentMedia).containsExactly(controlCommonModel)
@@ -758,7 +755,15 @@
mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData)
// THEN we should treat the media as active instead
- val dataCurrentAndActive = dataCurrent.copy(active = true)
+ val dataCurrentAndActive =
+ dataMain.copy(active = true, lastActive = clock.elapsedRealtime())
+ controlCommonModel =
+ controlCommonModel.copy(
+ mediaLoadingModel.copy(
+ receivedSmartspaceCardLatency = 100,
+ isSsReactivated = true
+ )
+ )
assertThat(currentMedia).containsExactly(controlCommonModel)
assertThat(
hasActiveMediaOrRecommendation(
@@ -800,11 +805,8 @@
val currentMedia by collectLastValue(repository.currentMedia)
// WHEN we have media that was recently played, but not currently active
val dataCurrent = dataMain.copy(active = false, lastActive = clock.elapsedRealtime())
- val controlCommonModel =
- MediaCommonModel.MediaControl(
- MediaDataLoadingModel.Loaded(dataMain.instanceId),
- true
- )
+ val mediaLoadingModel = MediaDataLoadingModel.Loaded(dataMain.instanceId)
+ var controlCommonModel = MediaCommonModel.MediaControl(mediaLoadingModel, true)
val recsCommonModel =
MediaCommonModel.MediaRecommendations(
SmartspaceMediaLoadingModel.Loaded(SMARTSPACE_KEY)
@@ -824,7 +826,8 @@
mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData)
// THEN we should treat the media as active instead
- val dataCurrentAndActive = dataCurrent.copy(active = true)
+ val dataCurrentAndActive =
+ dataMain.copy(active = true, lastActive = clock.elapsedRealtime())
verify(listener)
.onMediaDataLoaded(
eq(KEY),
@@ -849,6 +852,13 @@
)
.isTrue()
// Smartspace update should also be propagated but not prioritized.
+ controlCommonModel =
+ controlCommonModel.copy(
+ mediaLoadingModel.copy(
+ receivedSmartspaceCardLatency = 100,
+ isSsReactivated = true
+ )
+ )
assertThat(currentMedia).containsExactly(controlCommonModel, recsCommonModel)
verify(listener)
.onSmartspaceMediaDataLoaded(eq(SMARTSPACE_KEY), eq(smartspaceData), eq(false))
@@ -909,7 +919,8 @@
runCurrent()
mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData)
- val dataCurrentAndActive = dataCurrent.copy(active = true)
+ val dataCurrentAndActive =
+ dataMain.copy(active = true, lastActive = clock.elapsedRealtime())
verify(listener)
.onMediaDataLoaded(
eq(KEY),
@@ -1063,11 +1074,8 @@
MediaCommonModel.MediaRecommendations(
SmartspaceMediaLoadingModel.Loaded(SMARTSPACE_KEY)
)
- val controlCommonModel =
- MediaCommonModel.MediaControl(
- MediaDataLoadingModel.Loaded(dataMain.instanceId),
- true
- )
+ val mediaLoadingModel = MediaDataLoadingModel.Loaded(dataMain.instanceId)
+ var controlCommonModel = MediaCommonModel.MediaControl(mediaLoadingModel, true)
// WHEN we have media that was recently played, but not currently active
val dataCurrent = dataMain.copy(active = false, lastActive = clock.elapsedRealtime())
mediaDataFilter.onMediaDataLoaded(KEY, null, dataCurrent)
@@ -1086,7 +1094,15 @@
mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData)
// THEN we should treat the media as active instead
- val dataCurrentAndActive = dataCurrent.copy(active = true)
+ val dataCurrentAndActive =
+ dataMain.copy(active = true, lastActive = clock.elapsedRealtime())
+ controlCommonModel =
+ controlCommonModel.copy(
+ mediaLoadingModel.copy(
+ receivedSmartspaceCardLatency = 100,
+ isSsReactivated = true
+ )
+ )
verify(listener)
.onMediaDataLoaded(
eq(KEY),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/shared/SmartspaceMediaDataTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/shared/SmartspaceMediaDataTest.kt
index 473dc47..868145d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/shared/SmartspaceMediaDataTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/shared/SmartspaceMediaDataTest.kt
@@ -18,6 +18,7 @@
import android.app.smartspace.SmartspaceAction
import android.graphics.drawable.Icon
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.internal.logging.InstanceId
import com.android.systemui.SysuiTestCase
@@ -26,8 +27,10 @@
import com.android.systemui.res.R
import com.google.common.truth.Truth.assertThat
import org.junit.Test
+import org.junit.runner.RunWith
@SmallTest
+@RunWith(AndroidJUnit4::class)
class SmartspaceMediaDataTest : SysuiTestCase() {
private val icon: Icon = Icon.createWithResource(context, R.drawable.ic_media_play)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/muteawait/MediaMuteAwaitConnectionManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/muteawait/MediaMuteAwaitConnectionManagerTest.kt
index 2a8967e..64acc59 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/muteawait/MediaMuteAwaitConnectionManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/muteawait/MediaMuteAwaitConnectionManagerTest.kt
@@ -24,6 +24,7 @@
import android.media.AudioDeviceInfo
import android.media.AudioManager
import android.media.AudioManager.MuteAwaitConnectionCallback.EVENT_CONNECTION
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.settingslib.media.DeviceIconUtil
import com.android.settingslib.media.LocalMediaManager
@@ -35,6 +36,7 @@
import com.android.systemui.util.time.FakeSystemClock
import org.junit.Before
import org.junit.Test
+import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
import org.mockito.Mock
import org.mockito.Mockito.never
@@ -45,6 +47,7 @@
@SmallTest
+@RunWith(AndroidJUnit4::class)
class MediaMuteAwaitConnectionManagerTest : SysuiTestCase() {
private lateinit var muteAwaitConnectionManager: MediaMuteAwaitConnectionManager
@Mock
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/nearby/NearbyMediaDevicesManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/nearby/NearbyMediaDevicesManagerTest.kt
index d9453d6..b9aa029 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/nearby/NearbyMediaDevicesManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/nearby/NearbyMediaDevicesManagerTest.kt
@@ -2,6 +2,7 @@
import android.media.INearbyMediaDevicesProvider
import android.media.INearbyMediaDevicesUpdateCallback
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import android.media.NearbyDevice
@@ -10,6 +11,7 @@
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
+import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
import org.mockito.Mock
import org.mockito.Mockito.anyInt
@@ -20,6 +22,7 @@
import org.mockito.MockitoAnnotations
@SmallTest
+@RunWith(AndroidJUnit4::class)
class NearbyMediaDevicesManagerTest : SysuiTestCase() {
private lateinit var manager: NearbyMediaDevicesManager
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelperTest.kt
index d828193..77807bf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelperTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelperTest.kt
@@ -19,6 +19,7 @@
import android.app.StatusBarManager
import android.content.Context
import android.media.MediaRoute2Info
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.media.taptotransfer.receiver.ChipStateReceiver
@@ -35,6 +36,7 @@
import com.google.common.truth.Truth.assertThat
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
@@ -43,6 +45,7 @@
import java.util.concurrent.Executor
@SmallTest
+@RunWith(AndroidJUnit4::class)
class MediaTttCommandLineHelperTest : SysuiTestCase() {
private val inlineExecutor = Executor { command -> command.run() }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttLoggerUtilsTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttLoggerUtilsTest.kt
index b322bb7..ab5c893 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttLoggerUtilsTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttLoggerUtilsTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.media.taptotransfer.common
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.dump.DumpManager
@@ -27,9 +28,11 @@
import java.io.StringWriter
import org.junit.Before
import org.junit.Test
+import org.junit.runner.RunWith
import org.mockito.Mockito.mock
@SmallTest
+@RunWith(AndroidJUnit4::class)
class MediaTttLoggerUtilsTest : SysuiTestCase() {
private lateinit var buffer: LogBuffer
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttUtilsTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttUtilsTest.kt
index 5c6d913..02123ba 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttUtilsTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttUtilsTest.kt
@@ -19,6 +19,7 @@
import android.content.pm.ApplicationInfo
import android.content.pm.PackageManager
import android.graphics.drawable.Drawable
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.res.R
import com.android.systemui.SysuiTestCase
@@ -30,12 +31,14 @@
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
+import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.Mockito
import org.mockito.Mockito.`when` as whenever
import org.mockito.MockitoAnnotations
@SmallTest
+@RunWith(AndroidJUnit4::class)
class MediaTttUtilsTest : SysuiTestCase() {
private lateinit var appIconFromPackageName: Drawable
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttReceiverLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttReceiverLoggerTest.kt
index 64f3fd3..cee71b5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttReceiverLoggerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttReceiverLoggerTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.media.taptotransfer.receiver
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.dump.DumpManager
@@ -27,9 +28,11 @@
import java.io.StringWriter
import org.junit.Before
import org.junit.Test
+import org.junit.runner.RunWith
import org.mockito.Mockito.mock
@SmallTest
+@RunWith(AndroidJUnit4::class)
class MediaTttReceiverLoggerTest : SysuiTestCase() {
private lateinit var buffer: LogBuffer
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttReceiverUiEventLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttReceiverUiEventLoggerTest.kt
index f557713..352443a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttReceiverUiEventLoggerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttReceiverUiEventLoggerTest.kt
@@ -1,5 +1,6 @@
package com.android.systemui.media.taptotransfer.receiver
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.internal.logging.InstanceId
import com.android.internal.logging.testing.UiEventLoggerFake
@@ -7,8 +8,10 @@
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
+import org.junit.runner.RunWith
@SmallTest
+@RunWith(AndroidJUnit4::class)
class MediaTttReceiverUiEventLoggerTest : SysuiTestCase() {
private lateinit var uiEventLoggerFake: UiEventLoggerFake
private lateinit var logger: MediaTttReceiverUiEventLogger
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderLoggerTest.kt
index ee3704c..af8b3ed 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderLoggerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderLoggerTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.media.taptotransfer.sender
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.internal.logging.InstanceId
import com.android.systemui.SysuiTestCase
@@ -28,9 +29,11 @@
import java.io.StringWriter
import org.junit.Before
import org.junit.Test
+import org.junit.runner.RunWith
import org.mockito.Mockito.mock
@SmallTest
+@RunWith(AndroidJUnit4::class)
class MediaTttSenderLoggerTest : SysuiTestCase() {
private lateinit var buffer: LogBuffer
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderUiEventLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderUiEventLoggerTest.kt
index bf26a2f..30b578a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderUiEventLoggerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderUiEventLoggerTest.kt
@@ -1,5 +1,6 @@
package com.android.systemui.media.taptotransfer.sender
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.internal.logging.InstanceId
import com.android.internal.logging.testing.UiEventLoggerFake
@@ -7,8 +8,10 @@
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
+import org.junit.runner.RunWith
@SmallTest
+@RunWith(AndroidJUnit4::class)
class MediaTttSenderUiEventLoggerTest : SysuiTestCase() {
private lateinit var uiEventLoggerFake: UiEventLoggerFake
private lateinit var logger: MediaTttSenderUiEventLogger
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/view/MediaProjectionRecentsViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/view/MediaProjectionRecentsViewControllerTest.kt
index f4c5ccf..b337ccf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/view/MediaProjectionRecentsViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/view/MediaProjectionRecentsViewControllerTest.kt
@@ -22,6 +22,7 @@
import android.os.Bundle
import android.view.View
import android.view.ViewGroup
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.Flags.FLAG_PSS_APP_SELECTOR_ABRUPT_EXIT_FIX
import com.android.systemui.Flags.FLAG_PSS_APP_SELECTOR_RECENTS_SPLIT_SCREEN
@@ -36,6 +37,7 @@
import java.util.Optional
import org.junit.Rule
import org.junit.Test
+import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
import org.mockito.ArgumentMatchers.eq
import org.mockito.Mockito.any
@@ -43,6 +45,7 @@
import org.mockito.Mockito.verify
@SmallTest
+@RunWith(AndroidJUnit4::class)
class MediaProjectionRecentsViewControllerTest : SysuiTestCase() {
@get:Rule val expect: Expect = Expect.create()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/view/TaskPreviewSizeProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/view/TaskPreviewSizeProviderTest.kt
index 9630ee3..55e52b7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/view/TaskPreviewSizeProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/view/TaskPreviewSizeProviderTest.kt
@@ -27,6 +27,7 @@
import android.view.WindowMetrics
import androidx.core.view.WindowInsetsCompat.Type
import androidx.lifecycle.LifecycleOwner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.mediaprojection.appselector.view.TaskPreviewSizeProvider.TaskPreviewSizeListener
@@ -38,8 +39,10 @@
import kotlin.math.min
import org.junit.Before
import org.junit.Test
+import org.junit.runner.RunWith
@SmallTest
+@RunWith(AndroidJUnit4::class)
class TaskPreviewSizeProviderTest : SysuiTestCase() {
private val lifecycleOwner = mock<LifecycleOwner>()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/view/WindowMetricsProviderImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/view/WindowMetricsProviderImplTest.kt
index fe18454..cc722aa 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/view/WindowMetricsProviderImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/view/WindowMetricsProviderImplTest.kt
@@ -5,14 +5,17 @@
import android.view.WindowManager
import android.view.WindowMetrics
import androidx.core.view.WindowInsetsCompat
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
import org.junit.Test
+import org.junit.runner.RunWith
@SmallTest
+@RunWith(AndroidJUnit4::class)
class WindowMetricsProviderImplTest : SysuiTestCase() {
private val windowManager = mock<WindowManager>()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/TaskbarDelegateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/TaskbarDelegateTest.kt
index bba275e..5ed8a11 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/TaskbarDelegateTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/TaskbarDelegateTest.kt
@@ -1,6 +1,7 @@
package com.android.systemui.navigationbar
import android.app.ActivityManager
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.dump.DumpManager
@@ -19,6 +20,7 @@
import java.util.Optional
import org.junit.Before
import org.junit.Test
+import org.junit.runner.RunWith
import org.mockito.ArgumentMatchers
import org.mockito.Mock
import org.mockito.Mockito.any
@@ -30,6 +32,7 @@
import org.mockito.MockitoAnnotations
@SmallTest
+@RunWith(AndroidJUnit4::class)
class TaskbarDelegateTest : SysuiTestCase() {
val DISPLAY_ID = 0;
val MODE_GESTURE = 0;
@@ -108,4 +111,4 @@
ArgumentMatchers.eq(true)
)
}
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSDisableFlagsLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/QSDisableFlagsLoggerTest.kt
index 9e5d3bd..cc3e27c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSDisableFlagsLoggerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSDisableFlagsLoggerTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.qs
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.dump.DumpManager
@@ -26,9 +27,11 @@
import java.io.PrintWriter
import java.io.StringWriter
import org.junit.Test
+import org.junit.runner.RunWith
import org.mockito.Mockito.mock
@SmallTest
+@RunWith(AndroidJUnit4::class)
class QSDisableFlagsLoggerTest : SysuiTestCase() {
private val buffer =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/panels/data/QSPreferencesRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/panels/data/QSPreferencesRepositoryTest.kt
index b0aa6dd..7c95dfe 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/panels/data/QSPreferencesRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/panels/data/QSPreferencesRepositoryTest.kt
@@ -19,7 +19,7 @@
import android.content.Context
import android.content.SharedPreferences
import android.content.pm.UserInfo
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
@@ -36,7 +36,7 @@
import org.junit.runner.RunWith
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class QSPreferencesRepositoryTest : SysuiTestCase() {
private val kosmos = testKosmos()
private val underTest = with(kosmos) { qsPreferencesRepository }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/panels/domain/interactor/IconLabelVisibilityInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/panels/domain/interactor/IconLabelVisibilityInteractorTest.kt
index 9b08432e..7ad904e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/panels/domain/interactor/IconLabelVisibilityInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/panels/domain/interactor/IconLabelVisibilityInteractorTest.kt
@@ -17,7 +17,7 @@
package com.android.systemui.qs.panels.domain.interactor
import android.content.pm.UserInfo
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
@@ -34,7 +34,7 @@
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class IconLabelVisibilityInteractorTest : SysuiTestCase() {
private val kosmos = testKosmos()
private val underTest = with(kosmos) { iconLabelVisibilityInteractor }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/InternetTileNewImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/InternetTileNewImplTest.kt
index 0683321..79cb51a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/InternetTileNewImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/InternetTileNewImplTest.kt
@@ -20,6 +20,7 @@
import android.service.quicksettings.Tile
import android.testing.TestableLooper
import android.testing.TestableLooper.RunWithLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.internal.logging.MetricsLogger
import com.android.systemui.res.R
@@ -54,12 +55,14 @@
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
+import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.MockitoAnnotations
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@RunWithLooper(setAsMainLooper = true)
+@RunWith(AndroidJUnit4::class)
class InternetTileNewImplTest : SysuiTestCase() {
lateinit var underTest: InternetTileNewImpl
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java
index 0d7a9e4..f866f74 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java
@@ -35,8 +35,8 @@
import android.os.Handler;
import android.os.RemoteException;
import android.os.UserHandle;
-import android.testing.AndroidTestingRunner;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.internal.logging.UiEventLogger;
@@ -60,7 +60,7 @@
import java.io.IOException;
import java.util.concurrent.Executor;
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@SmallTest
public class RecordingServiceTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialogDelegateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialogDelegateTest.kt
index 9432451..db607fd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialogDelegateTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialogDelegateTest.kt
@@ -18,10 +18,10 @@
import android.content.Intent
import android.os.UserHandle
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.view.View
import android.widget.Spinner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.Dependency
import com.android.systemui.SysuiTestCase
@@ -55,7 +55,7 @@
import org.mockito.MockitoAnnotations
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
class ScreenRecordPermissionDialogDelegateTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/data/repository/ScreenRecordRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/data/repository/ScreenRecordRepositoryTest.kt
index 61ea437..aceea90 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/data/repository/ScreenRecordRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/data/repository/ScreenRecordRepositoryTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.screenrecord.data.repository
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
@@ -28,6 +29,7 @@
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Test
+import org.junit.runner.RunWith
import org.mockito.kotlin.argumentCaptor
import org.mockito.kotlin.mock
import org.mockito.kotlin.verify
@@ -35,6 +37,7 @@
@SmallTest
@OptIn(ExperimentalCoroutinesApi::class)
+@RunWith(AndroidJUnit4::class)
class ScreenRecordRepositoryTest : SysuiTestCase() {
private val kosmos = Kosmos()
private val testScope = kosmos.testScope
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionIntentCreatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionIntentCreatorTest.kt
index 36639d4..67eaf7b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionIntentCreatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionIntentCreatorTest.kt
@@ -20,6 +20,7 @@
import android.content.Context
import android.content.Intent
import android.net.Uri
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.ext.truth.content.IntentSubject.assertThat as assertThatIntent
import androidx.test.filters.SmallTest
import com.android.systemui.res.R
@@ -29,9 +30,11 @@
import com.google.common.truth.Truth.assertThat
import com.google.common.truth.Truth.assertWithMessage
import org.junit.Test
+import org.junit.runner.RunWith
import org.mockito.Mockito.`when` as whenever
@SmallTest
+@RunWith(AndroidJUnit4::class)
class ActionIntentCreatorTest : SysuiTestCase() {
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionIntentExecutorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionIntentExecutorTest.kt
index 5cd3f66..612d646 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionIntentExecutorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionIntentExecutorTest.kt
@@ -17,9 +17,9 @@
package com.android.systemui.screenshot
import android.content.Intent
+import androidx.test.ext.junit.runners.AndroidJUnit4
import android.os.Process.myUserHandle
import android.platform.test.annotations.EnableFlags
-import android.testing.AndroidTestingRunner
import android.testing.TestableContext
import com.android.systemui.Flags
import com.android.systemui.SysuiTestCase
@@ -36,7 +36,7 @@
import org.mockito.kotlin.mock
import org.mockito.kotlin.verify
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class ActionIntentExecutorTest : SysuiTestCase() {
private val scheduler = TestCoroutineScheduler()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/DefaultScreenshotActionsProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/DefaultScreenshotActionsProviderTest.kt
index 6f5c56e..148a2e5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/DefaultScreenshotActionsProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/DefaultScreenshotActionsProviderTest.kt
@@ -24,6 +24,7 @@
import androidx.test.filters.SmallTest
import com.android.internal.logging.UiEventLogger
import com.android.systemui.SysuiTestCase
+import com.android.systemui.screenshot.ui.viewmodel.PreviewAction
import com.google.common.truth.Truth.assertThat
import java.util.UUID
import kotlin.test.Test
@@ -60,9 +61,9 @@
fun previewActionAccessed_beforeScreenshotCompleted_doesNothing() {
actionsProvider = createActionsProvider()
- val previewActionCaptor = argumentCaptor<() -> Unit>()
+ val previewActionCaptor = argumentCaptor<PreviewAction>()
verify(actionsCallback).providePreviewAction(previewActionCaptor.capture())
- previewActionCaptor.firstValue.invoke()
+ previewActionCaptor.firstValue.onClick.invoke()
verifyNoMoreInteractions(actionExecutor)
}
@@ -102,14 +103,14 @@
fun actionAccessed_whilePending_launchesMostRecentAction() = runTest {
actionsProvider = createActionsProvider()
- val previewActionCaptor = argumentCaptor<() -> Unit>()
+ val previewActionCaptor = argumentCaptor<PreviewAction>()
verify(actionsCallback).providePreviewAction(previewActionCaptor.capture())
val actionButtonCaptor = argumentCaptor<() -> Unit>()
verify(actionsCallback, times(2))
.provideActionButton(any(), any(), actionButtonCaptor.capture())
actionButtonCaptor.firstValue.invoke()
- previewActionCaptor.firstValue.invoke()
+ previewActionCaptor.firstValue.onClick.invoke()
actionButtonCaptor.secondValue.invoke()
actionsProvider.setCompletedScreenshot(validResult)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/DraggableConstraintLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/DraggableConstraintLayoutTest.java
index c6ce51a..ba330f7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/DraggableConstraintLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/DraggableConstraintLayoutTest.java
@@ -20,10 +20,10 @@
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.MotionEvent;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -35,7 +35,7 @@
import org.mockito.MockitoAnnotations;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
public class DraggableConstraintLayoutTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/MessageContainerControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/MessageContainerControllerTest.kt
index 924b872..b31d21e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/MessageContainerControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/MessageContainerControllerTest.kt
@@ -4,12 +4,12 @@
import android.os.UserHandle
import android.platform.test.annotations.DisableFlags
import android.platform.test.annotations.EnableFlags
-import android.testing.AndroidTestingRunner
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.constraintlayout.widget.Guideline
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.screenshot.message.LabeledIcon
@@ -31,7 +31,7 @@
import org.mockito.MockitoAnnotations
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class MessageContainerControllerTest : SysuiTestCase() {
lateinit var messageContainer: MessageContainerController
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotActionsControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotActionsControllerTest.kt
index 2a3c31a..29e7a8a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotActionsControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotActionsControllerTest.kt
@@ -16,9 +16,10 @@
package com.android.systemui.screenshot
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.screenshot.ui.viewmodel.PreviewAction
import com.android.systemui.screenshot.ui.viewmodel.ScreenshotViewModel
import java.util.UUID
import kotlin.test.Test
@@ -29,13 +30,13 @@
import org.mockito.kotlin.never
import org.mockito.kotlin.verify
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
class ScreenshotActionsControllerTest : SysuiTestCase() {
private val screenshotData = mock<ScreenshotData>()
private val actionExecutor = mock<ActionExecutor>()
private val viewModel = mock<ScreenshotViewModel>()
- private val onClick = mock<() -> Unit>()
+ private val previewAction = PreviewAction("description", onClick = {})
private lateinit var actionsController: ScreenshotActionsController
private lateinit var fakeActionsProvider1: FakeActionsProvider
@@ -43,6 +44,7 @@
private val actionsProviderFactory =
object : ScreenshotActionsProvider.Factory {
var isFirstCall = true
+
override fun create(
requestId: UUID,
request: ScreenshotData,
@@ -69,16 +71,16 @@
@Test
fun setPreview_onCurrentScreenshot_updatesViewModel() {
actionsController.setCurrentScreenshot(screenshotData)
- fakeActionsProvider1.callPreview(onClick)
+ fakeActionsProvider1.callPreview(previewAction)
- verify(viewModel).setPreviewAction(onClick)
+ verify(viewModel).setPreviewAction(previewAction)
}
@Test
fun setPreview_onNonCurrentScreenshot_doesNotUpdateViewModel() {
actionsController.setCurrentScreenshot(screenshotData)
actionsController.setCurrentScreenshot(screenshotData)
- fakeActionsProvider1.callPreview(onClick)
+ fakeActionsProvider1.callPreview(previewAction)
verify(viewModel, never()).setPreviewAction(any())
}
@@ -87,8 +89,8 @@
private val actionsCallback: ScreenshotActionsController.ActionsCallback
) : ScreenshotActionsProvider {
- fun callPreview(onClick: () -> Unit) {
- actionsCallback.providePreviewAction(onClick)
+ fun callPreview(previewAction: PreviewAction) {
+ actionsCallback.providePreviewAction(previewAction)
}
override fun onScrollChipReady(onClick: Runnable) {}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotDataTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotDataTest.kt
index f8a8a68..3ed0977 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotDataTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotDataTest.kt
@@ -17,6 +17,7 @@
package com.android.systemui.screenshot
import android.content.ComponentName
+import androidx.test.ext.junit.runners.AndroidJUnit4
import android.graphics.Insets
import android.graphics.Rect
import android.os.UserHandle
@@ -25,7 +26,9 @@
import com.android.internal.util.ScreenshotRequest
import com.google.common.truth.Truth.assertThat
import org.junit.Test
+import org.junit.runner.RunWith
+@RunWith(AndroidJUnit4::class)
class ScreenshotDataTest {
private val type = WindowManager.TAKE_SCREENSHOT_FULLSCREEN
private val source = WindowManager.ScreenshotSource.SCREENSHOT_KEY_OTHER
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotNotificationSmartActionsTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotNotificationSmartActionsTest.java
index 2a9aca7..89c13b0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotNotificationSmartActionsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotNotificationSmartActionsTest.java
@@ -34,8 +34,8 @@
import android.net.Uri;
import android.os.Handler;
import android.os.UserHandle;
-import android.testing.AndroidTestingRunner;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -50,7 +50,7 @@
import java.util.concurrent.TimeUnit;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
/**
* Tests for exception handling and bitmap configuration in adding smart actions to Screenshot
* Notification.
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotSoundControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotSoundControllerTest.kt
index 92c2404..5987e74 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotSoundControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotSoundControllerTest.kt
@@ -17,6 +17,7 @@
package com.android.systemui.screenshot
import android.media.MediaPlayer
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.util.mockito.mock
@@ -29,11 +30,13 @@
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
+import org.junit.runner.RunWith
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
@SmallTest
@OptIn(ExperimentalCoroutinesApi::class)
+@RunWith(AndroidJUnit4::class)
class ScreenshotSoundControllerTest : SysuiTestCase() {
private val soundProvider = mock<ScreenshotSoundProvider>()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/SmartActionsReceiverTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/SmartActionsReceiverTest.java
index 83c9497..471fdc0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/SmartActionsReceiverTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/SmartActionsReceiverTest.java
@@ -28,8 +28,8 @@
import android.app.PendingIntent;
import android.content.Intent;
import android.os.Bundle;
-import android.testing.AndroidTestingRunner;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -40,7 +40,7 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@SmallTest
public class SmartActionsReceiverTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotExecutorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotExecutorTest.kt
index dd6ba90..ec5589e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotExecutorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotExecutorTest.kt
@@ -14,6 +14,7 @@
import android.view.Display.TYPE_WIFI
import android.view.WindowManager
import android.view.WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.internal.logging.testing.UiEventLoggerFake
import com.android.internal.util.ScreenshotRequest
@@ -42,7 +43,7 @@
import org.mockito.Mockito.verify
import org.mockito.Mockito.verifyNoMoreInteractions
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
class TakeScreenshotExecutorTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/WorkProfileMessageControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/WorkProfileMessageControllerTest.java
index ebdc49f..7d2d7c45 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/WorkProfileMessageControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/WorkProfileMessageControllerTest.java
@@ -30,12 +30,12 @@
import android.graphics.drawable.Drawable;
import android.os.UserHandle;
import android.os.UserManager;
-import android.testing.AndroidTestingRunner;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -54,7 +54,7 @@
import java.util.concurrent.TimeUnit;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
public class WorkProfileMessageControllerTest extends SysuiTestCase {
private static final String FILES_APP_COMPONENT = "com.android.test/.FilesComponent";
private static final String FILES_APP_LABEL = "Custom Files App";
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsActivityTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsActivityTest.java
index 68a6893..2981590 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsActivityTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsActivityTest.java
@@ -17,6 +17,7 @@
package com.android.systemui.screenshot.appclips;
import static android.app.Activity.RESULT_OK;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static com.android.systemui.screenshot.appclips.AppClipsEvent.SCREENSHOT_FOR_NOTE_ACCEPTED;
import static com.android.systemui.screenshot.appclips.AppClipsEvent.SCREENSHOT_FOR_NOTE_CANCELLED;
@@ -25,30 +26,45 @@
import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.app.ActivityTaskManager.RootTaskInfo;
+import android.app.IActivityTaskManager;
+import android.app.assist.AssistContent;
+import android.content.ComponentName;
import android.content.Intent;
+import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.ApplicationInfoFlags;
+import android.content.pm.ResolveInfo;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Process;
+import android.os.RemoteException;
import android.os.ResultReceiver;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
import android.testing.AndroidTestingRunner;
import android.view.Display;
+import android.view.View;
import android.widget.ImageView;
+import android.widget.TextView;
import androidx.test.rule.ActivityTestRule;
import androidx.test.runner.intercepting.SingleActivityFactory;
import com.android.internal.logging.UiEventLogger;
+import com.android.systemui.Flags;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.res.R;
+import com.android.systemui.screenshot.AssistContentRequester;
import com.android.systemui.screenshot.ImageExporter;
import com.android.systemui.settings.UserTracker;
@@ -60,9 +76,11 @@
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.List;
import java.util.UUID;
import java.util.concurrent.Executor;
import java.util.function.BiConsumer;
@@ -75,14 +93,27 @@
private static final Bitmap TEST_BITMAP = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888);
private static final String TEST_URI_STRING = "www.test-uri.com";
private static final Uri TEST_URI = Uri.parse(TEST_URI_STRING);
- private static final BiConsumer<Integer, Bundle> FAKE_CONSUMER = (unUsed1, unUsed2) -> {};
+ private static final BiConsumer<Integer, Bundle> FAKE_CONSUMER = (unUsed1, unUsed2) -> {
+ };
private static final String TEST_CALLING_PACKAGE = "test-calling-package";
+ private static final int BACKLINKS_TASK_ID = 42;
+ private static final String BACKLINKS_TASK_APP_NAME = "Backlinks app";
+ private static final String BACKLINKS_TASK_PACKAGE_NAME = "backlinksTaskPackageName";
+ private static final RootTaskInfo TASK_THAT_SUPPORTS_BACKLINKS =
+ createTaskInfoForBacklinksTask();
+
+ private static final AssistContent ASSIST_CONTENT_FOR_BACKLINKS_TASK =
+ createAssistContentForBacklinksTask();
@Mock
private AppClipsCrossProcessHelper mAppClipsCrossProcessHelper;
@Mock
private ImageExporter mImageExporter;
@Mock
+ private IActivityTaskManager mAtmService;
+ @Mock
+ private AssistContentRequester mAssistContentRequester;
+ @Mock
private PackageManager mPackageManager;
@Mock
private UserTracker mUserTracker;
@@ -98,9 +129,10 @@
protected AppClipsActivityTestable create(Intent unUsed) {
return new AppClipsActivityTestable(
new AppClipsViewModel.Factory(mAppClipsCrossProcessHelper,
- mImageExporter, getContext().getMainExecutor(),
- directExecutor()), mPackageManager, mUserTracker,
- mUiEventLogger);
+ mImageExporter, mAtmService, mAssistContentRequester,
+ mPackageManager, getContext().getMainExecutor(),
+ directExecutor()),
+ mPackageManager, mUserTracker, mUiEventLogger);
}
};
@@ -118,7 +150,7 @@
when(mPackageManager.getApplicationInfoAsUser(eq(TEST_CALLING_PACKAGE),
any(ApplicationInfoFlags.class), eq(TEST_USER_ID))).thenReturn(applicationInfo);
- when(mAppClipsCrossProcessHelper.takeScreenshot()).thenReturn(TEST_BITMAP);
+ when(mAppClipsCrossProcessHelper.takeScreenshot(anyInt())).thenReturn(TEST_BITMAP);
ImageExporter.Result result = new ImageExporter.Result();
result.uri = TEST_URI;
when(mImageExporter.export(any(Executor.class), any(UUID.class), any(Bitmap.class),
@@ -132,10 +164,13 @@
}
@Test
+ @DisableFlags(Flags.FLAG_APP_CLIPS_BACKLINKS)
public void appClipsLaunched_screenshotDisplayed() {
launchActivity();
assertThat(((ImageView) mActivity.findViewById(R.id.preview)).getDrawable()).isNotNull();
+ assertThat(mActivity.findViewById(R.id.backlinks_data).getVisibility())
+ .isEqualTo(View.GONE);
}
@Test
@@ -176,6 +211,32 @@
verify(mUiEventLogger).log(SCREENSHOT_FOR_NOTE_CANCELLED, TEST_UID, TEST_CALLING_PACKAGE);
}
+ @Test
+ @EnableFlags(Flags.FLAG_APP_CLIPS_BACKLINKS)
+ public void appClipsLaunched_backlinks_displayed() throws RemoteException {
+ // Set up mocking to verify backlinks view is displayed on screen.
+ ArgumentCaptor<Integer> displayIdCaptor = ArgumentCaptor.forClass(Integer.class);
+ when(mAtmService.getAllRootTaskInfosOnDisplay(displayIdCaptor.capture()))
+ .thenReturn(List.of(TASK_THAT_SUPPORTS_BACKLINKS));
+ doAnswer(invocation -> {
+ AssistContentRequester.Callback callback = invocation.getArgument(1);
+ callback.onAssistContentAvailable(ASSIST_CONTENT_FOR_BACKLINKS_TASK);
+ return null;
+ }).when(mAssistContentRequester).requestAssistContent(eq(BACKLINKS_TASK_ID), any());
+ when(mPackageManager
+ .resolveActivity(any(Intent.class), anyInt()))
+ .thenReturn(createBacklinksTaskResolveInfo());
+
+ launchActivity();
+ waitForIdleSync();
+
+ assertThat(displayIdCaptor.getValue()).isEqualTo(mActivity.getDisplayId());
+ TextView backlinksData = mActivity.findViewById(R.id.backlinks_data);
+ assertThat(backlinksData.getVisibility()).isEqualTo(View.VISIBLE);
+ assertThat(backlinksData.getText().toString()).isEqualTo(
+ mActivity.getString(R.string.backlinks_string, BACKLINKS_TASK_APP_NAME));
+ }
+
private void launchActivity() {
launchActivity(createResultReceiver(FAKE_CONSUMER));
}
@@ -203,7 +264,7 @@
testReceiver.writeToParcel(parcel, 0);
parcel.setDataPosition(0);
- testReceiver = ResultReceiver.CREATOR.createFromParcel(parcel);
+ testReceiver = ResultReceiver.CREATOR.createFromParcel(parcel);
parcel.recycle();
return testReceiver;
}
@@ -212,6 +273,37 @@
mContext.getMainExecutor().execute(runnable);
}
+ private static ResolveInfo createBacklinksTaskResolveInfo() {
+ ActivityInfo activityInfo = new ActivityInfo();
+ activityInfo.applicationInfo = new ApplicationInfo();
+ activityInfo.name = BACKLINKS_TASK_APP_NAME;
+ activityInfo.packageName = BACKLINKS_TASK_PACKAGE_NAME;
+ activityInfo.applicationInfo.packageName = BACKLINKS_TASK_PACKAGE_NAME;
+ ResolveInfo resolveInfo = new ResolveInfo();
+ resolveInfo.activityInfo = activityInfo;
+ return resolveInfo;
+ }
+
+ private static RootTaskInfo createTaskInfoForBacklinksTask() {
+ RootTaskInfo taskInfo = new RootTaskInfo();
+ taskInfo.taskId = BACKLINKS_TASK_ID;
+ taskInfo.isVisible = true;
+ taskInfo.isRunning = true;
+ taskInfo.numActivities = 1;
+ taskInfo.topActivity = new ComponentName(BACKLINKS_TASK_PACKAGE_NAME, "backlinksClass");
+ taskInfo.topActivityInfo = createBacklinksTaskResolveInfo().activityInfo;
+ taskInfo.baseIntent = new Intent().setComponent(taskInfo.topActivity);
+ taskInfo.childTaskIds = new int[]{BACKLINKS_TASK_ID + 1};
+ taskInfo.configuration.windowConfiguration.setActivityType(ACTIVITY_TYPE_STANDARD);
+ return taskInfo;
+ }
+
+ private static AssistContent createAssistContentForBacklinksTask() {
+ AssistContent content = new AssistContent();
+ content.setWebUri(Uri.parse("https://developers.android.com"));
+ return content;
+ }
+
public static class AppClipsActivityTestable extends AppClipsActivity {
public AppClipsActivityTestable(AppClipsViewModel.Factory viewModelFactory,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsViewModelTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsViewModelTest.java
index ad0797c..dcb75d1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsViewModelTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsViewModelTest.java
@@ -16,28 +16,51 @@
package com.android.systemui.screenshot.appclips;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.content.ClipDescription.MIMETYPE_TEXT_INTENT;
+import static android.content.ClipDescription.MIMETYPE_TEXT_URILIST;
+import static android.content.Intent.ACTION_MAIN;
+import static android.content.Intent.ACTION_VIEW;
import static android.content.Intent.CAPTURE_CONTENT_FOR_NOTE_FAILED;
+import static android.content.Intent.CATEGORY_LAUNCHER;
+import static android.view.Display.DEFAULT_DISPLAY;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.app.ActivityTaskManager.RootTaskInfo;
+import android.app.IActivityTaskManager;
+import android.app.assist.AssistContent;
+import android.content.ClipData;
+import android.content.ClipDescription;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
import android.graphics.Bitmap;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.ShapeDrawable;
import android.net.Uri;
import android.os.Process;
+import android.os.RemoteException;
import android.os.UserHandle;
-import android.view.Display;
import androidx.test.runner.AndroidJUnit4;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.screenshot.AssistContentRequester;
import com.android.systemui.screenshot.ImageExporter;
import com.google.common.util.concurrent.Futures;
@@ -45,9 +68,13 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
@@ -60,27 +87,44 @@
private static final Rect FAKE_RECT = new Rect();
private static final Uri FAKE_URI = Uri.parse("www.test-uri.com");
private static final UserHandle USER_HANDLE = Process.myUserHandle();
+ private static final int BACKLINKS_TASK_ID = 42;
+ private static final String BACKLINKS_TASK_APP_NAME = "Ultimate question app";
+ private static final String BACKLINKS_TASK_PACKAGE_NAME = "backlinksTaskPackageName";
+ private static final AssistContent EMPTY_ASSIST_CONTENT = new AssistContent();
@Mock private AppClipsCrossProcessHelper mAppClipsCrossProcessHelper;
@Mock private ImageExporter mImageExporter;
+ @Mock private IActivityTaskManager mAtmService;
+ @Mock private AssistContentRequester mAssistContentRequester;
+ @Mock
+ private PackageManager mPackageManager;
+ private ArgumentCaptor<Intent> mPackageManagerIntentCaptor;
private AppClipsViewModel mViewModel;
@Before
- public void setUp() {
+ public void setUp() throws RemoteException {
MockitoAnnotations.initMocks(this);
+ mPackageManagerIntentCaptor = ArgumentCaptor.forClass(Intent.class);
+
+ // Set up mocking for backlinks.
+ when(mAtmService.getAllRootTaskInfosOnDisplay(DEFAULT_DISPLAY))
+ .thenReturn(List.of(createTaskInfoForBacklinksTask()));
+ when(mPackageManager.resolveActivity(mPackageManagerIntentCaptor.capture(), anyInt()))
+ .thenReturn(createBacklinksTaskResolveInfo());
mViewModel = new AppClipsViewModel.Factory(mAppClipsCrossProcessHelper, mImageExporter,
+ mAtmService, mAssistContentRequester, mPackageManager,
getContext().getMainExecutor(), directExecutor()).create(AppClipsViewModel.class);
}
@Test
public void performScreenshot_fails_shouldUpdateErrorWithFailed() {
- when(mAppClipsCrossProcessHelper.takeScreenshot()).thenReturn(null);
+ when(mAppClipsCrossProcessHelper.takeScreenshot(anyInt())).thenReturn(null);
- mViewModel.performScreenshot();
+ mViewModel.performScreenshot(DEFAULT_DISPLAY);
waitForIdleSync();
- verify(mAppClipsCrossProcessHelper).takeScreenshot();
+ verify(mAppClipsCrossProcessHelper).takeScreenshot(DEFAULT_DISPLAY);
assertThat(mViewModel.getErrorLiveData().getValue())
.isEqualTo(CAPTURE_CONTENT_FOR_NOTE_FAILED);
assertThat(mViewModel.getResultLiveData().getValue()).isNull();
@@ -88,12 +132,12 @@
@Test
public void performScreenshot_succeeds_shouldUpdateScreenshotWithBitmap() {
- when(mAppClipsCrossProcessHelper.takeScreenshot()).thenReturn(FAKE_BITMAP);
+ when(mAppClipsCrossProcessHelper.takeScreenshot(DEFAULT_DISPLAY)).thenReturn(FAKE_BITMAP);
- mViewModel.performScreenshot();
+ mViewModel.performScreenshot(DEFAULT_DISPLAY);
waitForIdleSync();
- verify(mAppClipsCrossProcessHelper).takeScreenshot();
+ verify(mAppClipsCrossProcessHelper).takeScreenshot(DEFAULT_DISPLAY);
assertThat(mViewModel.getErrorLiveData().getValue()).isNull();
assertThat(mViewModel.getScreenshot().getValue()).isEqualTo(FAKE_BITMAP);
}
@@ -101,7 +145,7 @@
@Test
public void saveScreenshot_throwsError_shouldUpdateErrorWithFailed() {
when(mImageExporter.export(any(Executor.class), any(UUID.class), eq(null), eq(USER_HANDLE),
- eq(Display.DEFAULT_DISPLAY))).thenReturn(
+ eq(DEFAULT_DISPLAY))).thenReturn(
Futures.immediateFailedFuture(new ExecutionException(new Throwable())));
mViewModel.saveScreenshotThenFinish(FAKE_DRAWABLE, FAKE_RECT, USER_HANDLE);
@@ -115,7 +159,7 @@
@Test
public void saveScreenshot_failsSilently_shouldUpdateErrorWithFailed() {
when(mImageExporter.export(any(Executor.class), any(UUID.class), eq(null), eq(USER_HANDLE),
- eq(Display.DEFAULT_DISPLAY))).thenReturn(
+ eq(DEFAULT_DISPLAY))).thenReturn(
Futures.immediateFuture(new ImageExporter.Result()));
mViewModel.saveScreenshotThenFinish(FAKE_DRAWABLE, FAKE_RECT, USER_HANDLE);
@@ -131,7 +175,7 @@
ImageExporter.Result result = new ImageExporter.Result();
result.uri = FAKE_URI;
when(mImageExporter.export(any(Executor.class), any(UUID.class), eq(null), eq(USER_HANDLE),
- eq(Display.DEFAULT_DISPLAY))).thenReturn(Futures.immediateFuture(result));
+ eq(DEFAULT_DISPLAY))).thenReturn(Futures.immediateFuture(result));
mViewModel.saveScreenshotThenFinish(FAKE_DRAWABLE, FAKE_RECT, USER_HANDLE);
waitForIdleSync();
@@ -139,4 +183,198 @@
assertThat(mViewModel.getErrorLiveData().getValue()).isNull();
assertThat(mViewModel.getResultLiveData().getValue()).isEqualTo(FAKE_URI);
}
+
+ @Test
+ public void triggerBacklinks_shouldUpdateBacklinks_withUri() {
+ Uri expectedUri = Uri.parse("https://developers.android.com");
+ AssistContent contentWithUri = new AssistContent();
+ contentWithUri.setWebUri(expectedUri);
+ doAnswer(invocation -> {
+ AssistContentRequester.Callback callback = invocation.getArgument(1);
+ callback.onAssistContentAvailable(contentWithUri);
+ return null;
+ }).when(mAssistContentRequester).requestAssistContent(eq(BACKLINKS_TASK_ID), any());
+
+ mViewModel.triggerBacklinks(Collections.emptySet(), DEFAULT_DISPLAY);
+ waitForIdleSync();
+
+ Intent queriedIntent = mPackageManagerIntentCaptor.getValue();
+ assertThat(queriedIntent.getData()).isEqualTo(expectedUri);
+ assertThat(queriedIntent.getAction()).isEqualTo(ACTION_VIEW);
+
+ ClipData result = mViewModel.getBacklinksLiveData().getValue();
+ ClipDescription resultDescription = result.getDescription();
+ assertThat(resultDescription.getLabel().toString()).isEqualTo(BACKLINKS_TASK_APP_NAME);
+ assertThat(resultDescription.getMimeType(0)).isEqualTo(MIMETYPE_TEXT_URILIST);
+ assertThat(result.getItemCount()).isEqualTo(1);
+ assertThat(result.getItemAt(0).getUri()).isEqualTo(expectedUri);
+ }
+
+ @Test
+ public void triggerBacklinks_withNonResolvableUri_usesMainLauncherIntent() {
+ Uri expectedUri = Uri.parse("https://developers.android.com");
+ AssistContent contentWithUri = new AssistContent();
+ contentWithUri.setWebUri(expectedUri);
+ resetPackageManagerMockingForUsingFallbackBacklinks();
+ doAnswer(invocation -> {
+ AssistContentRequester.Callback callback = invocation.getArgument(1);
+ callback.onAssistContentAvailable(contentWithUri);
+ return null;
+ }).when(mAssistContentRequester).requestAssistContent(eq(BACKLINKS_TASK_ID), any());
+
+ mViewModel.triggerBacklinks(Collections.emptySet(), DEFAULT_DISPLAY);
+ waitForIdleSync();
+
+ verifyMainLauncherBacklinksIntent();
+ }
+
+ @Test
+ public void triggerBacklinks_shouldUpdateBacklinks_withAppProvidedIntent() {
+ Intent expectedIntent = new Intent().setPackage(BACKLINKS_TASK_PACKAGE_NAME);
+ AssistContent contentWithAppProvidedIntent = new AssistContent();
+ contentWithAppProvidedIntent.setIntent(expectedIntent);
+ doAnswer(invocation -> {
+ AssistContentRequester.Callback callback = invocation.getArgument(1);
+ callback.onAssistContentAvailable(contentWithAppProvidedIntent);
+ return null;
+ }).when(mAssistContentRequester).requestAssistContent(eq(BACKLINKS_TASK_ID), any());
+
+ mViewModel.triggerBacklinks(Collections.emptySet(), DEFAULT_DISPLAY);
+ waitForIdleSync();
+
+ Intent queriedIntent = mPackageManagerIntentCaptor.getValue();
+ assertThat(queriedIntent.getPackage()).isEqualTo(expectedIntent.getPackage());
+
+ ClipData result = mViewModel.getBacklinksLiveData().getValue();
+ ClipDescription resultDescription = result.getDescription();
+ assertThat(resultDescription.getLabel().toString()).isEqualTo(BACKLINKS_TASK_APP_NAME);
+ assertThat(resultDescription.getMimeType(0)).isEqualTo(MIMETYPE_TEXT_INTENT);
+ assertThat(result.getItemCount()).isEqualTo(1);
+ assertThat(result.getItemAt(0).getIntent()).isEqualTo(expectedIntent);
+ }
+
+ @Test
+ public void triggerBacklinks_withNonResolvableAppProvidedIntent_usesMainLauncherIntent() {
+ Intent expectedIntent = new Intent().setPackage(BACKLINKS_TASK_PACKAGE_NAME);
+ AssistContent contentWithAppProvidedIntent = new AssistContent();
+ contentWithAppProvidedIntent.setIntent(expectedIntent);
+ resetPackageManagerMockingForUsingFallbackBacklinks();
+ doAnswer(invocation -> {
+ AssistContentRequester.Callback callback = invocation.getArgument(1);
+ callback.onAssistContentAvailable(contentWithAppProvidedIntent);
+ return null;
+ }).when(mAssistContentRequester).requestAssistContent(eq(BACKLINKS_TASK_ID), any());
+
+ mViewModel.triggerBacklinks(Collections.emptySet(), DEFAULT_DISPLAY);
+ waitForIdleSync();
+
+ verifyMainLauncherBacklinksIntent();
+ }
+
+ @Test
+ public void triggerBacklinks_shouldUpdateBacklinks_withMainLauncherIntent() {
+ doAnswer(invocation -> {
+ AssistContentRequester.Callback callback = invocation.getArgument(1);
+ callback.onAssistContentAvailable(EMPTY_ASSIST_CONTENT);
+ return null;
+ }).when(mAssistContentRequester).requestAssistContent(eq(BACKLINKS_TASK_ID), any());
+
+ mViewModel.triggerBacklinks(Collections.emptySet(), DEFAULT_DISPLAY);
+ waitForIdleSync();
+
+ Intent queriedIntent = mPackageManagerIntentCaptor.getValue();
+ assertThat(queriedIntent.getPackage()).isEqualTo(BACKLINKS_TASK_PACKAGE_NAME);
+ assertThat(queriedIntent.getAction()).isEqualTo(ACTION_MAIN);
+ assertThat(queriedIntent.getCategories()).containsExactly(CATEGORY_LAUNCHER);
+
+ verifyMainLauncherBacklinksIntent();
+ }
+
+ @Test
+ public void triggerBacklinks_withNonResolvableMainLauncherIntent_noBacklinksAvailable() {
+ reset(mPackageManager);
+ doAnswer(invocation -> {
+ AssistContentRequester.Callback callback = invocation.getArgument(1);
+ callback.onAssistContentAvailable(EMPTY_ASSIST_CONTENT);
+ return null;
+ }).when(mAssistContentRequester).requestAssistContent(eq(BACKLINKS_TASK_ID), any());
+
+ mViewModel.triggerBacklinks(Collections.emptySet(), DEFAULT_DISPLAY);
+ waitForIdleSync();
+
+ assertThat(mViewModel.getBacklinksLiveData().getValue()).isNull();
+ }
+
+ @Test
+ public void triggerBacklinks_nonStandardActivityIgnored_noBacklinkAvailable()
+ throws RemoteException {
+ reset(mAtmService);
+ RootTaskInfo taskInfo = createTaskInfoForBacklinksTask();
+ taskInfo.configuration.windowConfiguration.setActivityType(ACTIVITY_TYPE_HOME);
+ when(mAtmService.getAllRootTaskInfosOnDisplay(DEFAULT_DISPLAY))
+ .thenReturn(List.of(taskInfo));
+
+ mViewModel.triggerBacklinks(Collections.emptySet(), DEFAULT_DISPLAY);
+ waitForIdleSync();
+
+ assertThat(mViewModel.getBacklinksLiveData().getValue()).isNull();
+ }
+
+ @Test
+ public void triggerBacklinks_taskIdsToIgnoreConsidered_noBacklinkAvailable() {
+ mViewModel.triggerBacklinks(Set.of(BACKLINKS_TASK_ID), DEFAULT_DISPLAY);
+ waitForIdleSync();
+
+ assertThat(mViewModel.getBacklinksLiveData().getValue()).isNull();
+ }
+
+ private void resetPackageManagerMockingForUsingFallbackBacklinks() {
+ reset(mPackageManager);
+ when(mPackageManager.resolveActivity(any(Intent.class), anyInt()))
+ // First the logic queries whether a package has a launcher activity, this should
+ // resolve otherwise the logic filters out the task.
+ .thenReturn(createBacklinksTaskResolveInfo())
+ // Then logic queries with the backlinks intent, this should not resolve for the
+ // logic to use the fallback intent.
+ .thenReturn(null);
+ }
+
+ private void verifyMainLauncherBacklinksIntent() {
+ ClipData result = mViewModel.getBacklinksLiveData().getValue();
+ assertThat(result.getItemCount()).isEqualTo(1);
+
+ ClipDescription resultDescription = result.getDescription();
+ assertThat(resultDescription.getLabel().toString()).isEqualTo(BACKLINKS_TASK_APP_NAME);
+ assertThat(resultDescription.getMimeType(0)).isEqualTo(MIMETYPE_TEXT_INTENT);
+
+ Intent actualBacklinksIntent = result.getItemAt(0).getIntent();
+ assertThat(actualBacklinksIntent.getPackage()).isEqualTo(BACKLINKS_TASK_PACKAGE_NAME);
+ assertThat(actualBacklinksIntent.getAction()).isEqualTo(ACTION_MAIN);
+ assertThat(actualBacklinksIntent.getCategories()).containsExactly(CATEGORY_LAUNCHER);
+ }
+
+ private static ResolveInfo createBacklinksTaskResolveInfo() {
+ ActivityInfo activityInfo = new ActivityInfo();
+ activityInfo.applicationInfo = new ApplicationInfo();
+ activityInfo.name = BACKLINKS_TASK_APP_NAME;
+ activityInfo.packageName = BACKLINKS_TASK_PACKAGE_NAME;
+ activityInfo.applicationInfo.packageName = BACKLINKS_TASK_PACKAGE_NAME;
+ ResolveInfo resolveInfo = new ResolveInfo();
+ resolveInfo.activityInfo = activityInfo;
+ return resolveInfo;
+ }
+
+ private static RootTaskInfo createTaskInfoForBacklinksTask() {
+ RootTaskInfo taskInfo = new RootTaskInfo();
+ taskInfo.taskId = BACKLINKS_TASK_ID;
+ taskInfo.isVisible = true;
+ taskInfo.isRunning = true;
+ taskInfo.numActivities = 1;
+ taskInfo.topActivity = new ComponentName(BACKLINKS_TASK_PACKAGE_NAME, "backlinksClass");
+ taskInfo.topActivityInfo = createBacklinksTaskResolveInfo().activityInfo;
+ taskInfo.baseIntent = new Intent().setComponent(taskInfo.topActivity);
+ taskInfo.childTaskIds = new int[]{BACKLINKS_TASK_ID + 1};
+ taskInfo.configuration.windowConfiguration.setActivityType(ACTIVITY_TYPE_STANDARD);
+ return taskInfo;
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/message/ProfileMessageControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/message/ProfileMessageControllerTest.kt
index ce2facd..6b9865f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/message/ProfileMessageControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/message/ProfileMessageControllerTest.kt
@@ -17,6 +17,7 @@
package com.android.systemui.screenshot.message
import android.content.ComponentName
+import androidx.test.ext.junit.runners.AndroidJUnit4
import android.content.pm.PackageManager
import android.graphics.Canvas
import android.graphics.ColorFilter
@@ -27,7 +28,9 @@
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.test.runTest
import org.junit.Test
+import org.junit.runner.RunWith
+@RunWith(AndroidJUnit4::class)
class ProfileMessageControllerTest {
@Test
fun personalScreenshot() = runTest {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/policy/PolicyRequestProcessorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/policy/PolicyRequestProcessorTest.kt
index 4945ace..3b0e194 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/policy/PolicyRequestProcessorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/policy/PolicyRequestProcessorTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.screenshot.policy
import android.content.ComponentName
+import androidx.test.ext.junit.runners.AndroidJUnit4
import android.graphics.Insets
import android.graphics.Rect
import android.os.UserHandle
@@ -34,7 +35,9 @@
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking
import org.junit.Test
+import org.junit.runner.RunWith
+@RunWith(AndroidJUnit4::class)
class PolicyRequestProcessorTest {
val imageCapture = object : ImageCapture {
@@ -78,4 +81,4 @@
assertWithMessage("The topComponent of the screenshot").that(result.topComponent)
.isEqualTo(ComponentName.unflattenFromString(FILES))
}
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/policy/PrivateProfilePolicyTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/policy/PrivateProfilePolicyTest.kt
index 9e3ae05..6e57761 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/policy/PrivateProfilePolicyTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/policy/PrivateProfilePolicyTest.kt
@@ -17,6 +17,7 @@
package com.android.systemui.screenshot.policy
import android.content.ComponentName
+import androidx.test.ext.junit.runners.AndroidJUnit4
import android.os.UserHandle
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.screenshot.data.model.DisplayContentModel
@@ -40,7 +41,9 @@
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.test.runTest
import org.junit.Test
+import org.junit.runner.RunWith
+@RunWith(AndroidJUnit4::class)
class PrivateProfilePolicyTest {
private val kosmos = Kosmos()
private val policy = PrivateProfilePolicy(kosmos.profileTypeRepository)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/policy/WorkProfilePolicyTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/policy/WorkProfilePolicyTest.kt
index 5d35528..8d217fc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/policy/WorkProfilePolicyTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/policy/WorkProfilePolicyTest.kt
@@ -17,6 +17,7 @@
package com.android.systemui.screenshot.policy
import android.content.ComponentName
+import androidx.test.ext.junit.runners.AndroidJUnit4
import android.os.UserHandle
import android.platform.test.annotations.DisableFlags
import android.platform.test.annotations.EnableFlags
@@ -50,7 +51,9 @@
import kotlinx.coroutines.test.runTest
import org.junit.Rule
import org.junit.Test
+import org.junit.runner.RunWith
+@RunWith(AndroidJUnit4::class)
class WorkProfilePolicyTest {
@JvmField @Rule val setFlagsRule = SetFlagsRule()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/scroll/FakeSessionTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/scroll/FakeSessionTest.java
index aad46139..88cb00c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/scroll/FakeSessionTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/scroll/FakeSessionTest.java
@@ -23,8 +23,8 @@
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
-import android.testing.AndroidTestingRunner;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -39,7 +39,7 @@
* client/connection.
*/
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
public class FakeSessionTest extends SysuiTestCase {
@Test
public void testNonEmptyResult_hasImage() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/scroll/ScrollCaptureControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/scroll/ScrollCaptureControllerTest.java
index f39f543..f8de714 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/scroll/ScrollCaptureControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/scroll/ScrollCaptureControllerTest.java
@@ -29,9 +29,9 @@
import static java.lang.Math.abs;
import android.content.Context;
-import android.testing.AndroidTestingRunner;
import android.view.ScrollCaptureResponse;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.internal.logging.testing.UiEventLoggerFake;
@@ -46,7 +46,7 @@
* screenshots.
*/
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
public class ScrollCaptureControllerTest extends SysuiTestCase {
private static final ScrollCaptureResponse EMPTY_RESPONSE =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ui/viewmodel/ScreenshotViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ui/viewmodel/ScreenshotViewModelTest.kt
index e32086b..e39e0fb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ui/viewmodel/ScreenshotViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ui/viewmodel/ScreenshotViewModelTest.kt
@@ -17,12 +17,15 @@
package com.android.systemui.screenshot.ui.viewmodel
import android.view.accessibility.AccessibilityManager
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.google.common.truth.Truth.assertThat
import org.junit.Test
+import org.junit.runner.RunWith
import org.mockito.Mockito.mock
@SmallTest
+@RunWith(AndroidJUnit4::class)
class ScreenshotViewModelTest {
private val accessibilityManager: AccessibilityManager = mock(AccessibilityManager::class.java)
private val appearance = ActionButtonAppearance(null, "Label", "Description")
diff --git a/packages/SystemUI/tests/src/com/android/systemui/scrim/ScrimViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/scrim/ScrimViewTest.java
index a345f78..ca8da63 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/scrim/ScrimViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/scrim/ScrimViewTest.java
@@ -22,12 +22,12 @@
import android.graphics.Rect;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
import android.testing.ViewUtils;
import android.view.View;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.internal.colorextraction.ColorExtractor;
@@ -38,7 +38,7 @@
import org.junit.Test;
import org.junit.runner.RunWith;
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@SmallTest
public class ScrimViewTest extends LeakCheckedTest {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/sensorprivacy/SensorUseStartedActivityTest.kt b/packages/SystemUI/tests/src/com/android/systemui/sensorprivacy/SensorUseStartedActivityTest.kt
index 333e634..1a4749c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/sensorprivacy/SensorUseStartedActivityTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/sensorprivacy/SensorUseStartedActivityTest.kt
@@ -1,8 +1,8 @@
package com.android.systemui.sensorprivacy
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import androidx.test.ext.junit.rules.ActivityScenarioRule
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.util.mockito.mock
@@ -11,7 +11,7 @@
import org.junit.Test
import org.junit.runner.RunWith
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
@TestableLooper.RunWithLooper
class SensorUseStartedActivityTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/settings/brightness/BrightnessControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/settings/brightness/BrightnessControllerTest.kt
index 2b78405..98260d8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/settings/brightness/BrightnessControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/settings/brightness/BrightnessControllerTest.kt
@@ -19,9 +19,9 @@
import android.hardware.display.DisplayManager
import android.os.Handler
import android.service.vr.IVrManager
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.testing.TestableLooper.RunWithLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.settings.DisplayTracker
@@ -40,7 +40,7 @@
import org.mockito.MockitoAnnotations
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@RunWithLooper
class BrightnessControllerTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/settings/brightness/BrightnessDialogTest.kt b/packages/SystemUI/tests/src/com/android/systemui/settings/brightness/BrightnessDialogTest.kt
index 31acd86..a06784e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/settings/brightness/BrightnessDialogTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/settings/brightness/BrightnessDialogTest.kt
@@ -18,11 +18,11 @@
import android.content.Intent
import android.graphics.Rect
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.view.View
import android.view.ViewGroup
import android.view.WindowManagerPolicyConstants.EXTRA_FROM_BRIGHTNESS_KEY
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.FlakyTest
import androidx.test.filters.SmallTest
import androidx.test.rule.ActivityTestRule
@@ -55,7 +55,7 @@
import org.mockito.MockitoAnnotations
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@TestableLooper.RunWithLooper
class BrightnessDialogTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/CombinedShadeHeaderConstraintsTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/CombinedShadeHeaderConstraintsTest.kt
index 2b3588a..c7bea59 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/CombinedShadeHeaderConstraintsTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/CombinedShadeHeaderConstraintsTest.kt
@@ -16,11 +16,11 @@
package com.android.systemui.shade
-import android.testing.AndroidTestingRunner
import android.view.ViewGroup
import androidx.constraintlayout.widget.ConstraintSet
import androidx.constraintlayout.widget.ConstraintSet.PARENT_ID
import androidx.constraintlayout.widget.ConstraintSet.START
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.res.R
import com.android.systemui.SysuiTestCase
@@ -33,7 +33,7 @@
import org.junit.runner.RunWith
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class CombinedShadeHeaderConstraintsTest : SysuiTestCase() {
private lateinit var qqsConstraint: ConstraintSet
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/ConstraintChangeTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/ConstraintChangeTest.kt
index 9b2e085..8c80835 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/ConstraintChangeTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/ConstraintChangeTest.kt
@@ -15,8 +15,8 @@
*/
package com.android.systemui.shade
-import android.testing.AndroidTestingRunner
import androidx.constraintlayout.widget.ConstraintSet
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.util.mockito.mock
@@ -27,7 +27,7 @@
import org.mockito.Mockito.verify
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class ConstraintChangeTest : SysuiTestCase() {
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/ConstraintChangesTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/ConstraintChangesTest.kt
index 0abb084..05c1706 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/ConstraintChangesTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/ConstraintChangesTest.kt
@@ -15,8 +15,8 @@
*/
package com.android.systemui.shade
-import android.testing.AndroidTestingRunner
import androidx.constraintlayout.widget.ConstraintSet
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.util.mockito.mock
@@ -26,7 +26,7 @@
import org.mockito.Mockito.inOrder
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class ConstraintChangesTest : SysuiTestCase() {
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/LockscreenHostedDreamGestureListenerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/LockscreenHostedDreamGestureListenerTest.kt
index b4f890b..2ac0ed0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/LockscreenHostedDreamGestureListenerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/LockscreenHostedDreamGestureListenerTest.kt
@@ -17,8 +17,8 @@
package com.android.systemui.shade
import android.os.PowerManager
-import android.testing.AndroidTestingRunner
import android.view.MotionEvent
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
@@ -47,7 +47,7 @@
@SmallTest
@OptIn(ExperimentalCoroutinesApi::class)
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class LockscreenHostedDreamGestureListenerTest : SysuiTestCase() {
@Mock private lateinit var falsingManager: FalsingManager
@Mock private lateinit var falsingCollector: FalsingCollector
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelUnfoldAnimationControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelUnfoldAnimationControllerTest.kt
index bff408a..abc96ee 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelUnfoldAnimationControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelUnfoldAnimationControllerTest.kt
@@ -16,9 +16,9 @@
package com.android.systemui.shade
-import android.testing.AndroidTestingRunner
import android.view.View
import android.view.ViewGroup
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.res.R
import com.android.systemui.SysuiTestCase
@@ -46,7 +46,7 @@
* the set of ids, which also dictact which direction to move and when, via a filter fn.
*/
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class NotificationPanelUnfoldAnimationControllerTest : SysuiTestCase() {
@Mock private lateinit var progressProvider: NaturalRotationUnfoldProgressProvider
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 13d44de..90e8ea5f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
@@ -47,13 +47,14 @@
import android.graphics.Point;
import android.os.PowerManager;
import android.platform.test.annotations.DisableFlags;
-import android.testing.AndroidTestingRunner;
+import android.platform.test.annotations.EnableFlags;
import android.testing.TestableLooper;
import android.view.MotionEvent;
import android.view.View;
import android.view.accessibility.AccessibilityNodeInfo;
import androidx.constraintlayout.widget.ConstraintSet;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.DejankUtils;
@@ -78,7 +79,7 @@
import java.util.List;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
public class NotificationPanelViewControllerTest extends NotificationPanelViewControllerBaseTest {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerWithCoroutinesTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerWithCoroutinesTest.kt
index d47bd47..e1d92e7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerWithCoroutinesTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerWithCoroutinesTest.kt
@@ -19,11 +19,11 @@
package com.android.systemui.shade
import android.platform.test.annotations.EnableFlags
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.view.HapticFeedbackConstants
import android.view.View
import android.view.ViewStub
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.internal.util.CollectionUtils
import com.android.keyguard.KeyguardClockSwitch.LARGE
@@ -55,7 +55,7 @@
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
@SmallTest
class NotificationPanelViewControllerWithCoroutinesTest :
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
index 31bd12f..fec7424 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
@@ -16,10 +16,10 @@
package com.android.systemui.shade
import android.os.SystemClock
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
import android.view.MotionEvent
import android.widget.FrameLayout
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.keyguard.KeyguardSecurityContainerController
import com.android.keyguard.LegacyLockIconViewController
@@ -82,7 +82,7 @@
import org.mockito.MockitoAnnotations
@ExperimentalCoroutinesApi
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@RunWithLooper(setAsMainLooper = true)
@SmallTest
class NotificationShadeWindowViewTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationsQuickSettingsContainerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationsQuickSettingsContainerTest.kt
index 0c3af03..97ce37c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationsQuickSettingsContainerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationsQuickSettingsContainerTest.kt
@@ -16,11 +16,11 @@
package com.android.systemui.shade
-import android.testing.AndroidTestingRunner
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import androidx.constraintlayout.widget.ConstraintLayout
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.qs.QSFragmentLegacy
@@ -34,7 +34,7 @@
import org.mockito.MockitoAnnotations
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class NotificationsQuickSettingsContainerTest : SysuiTestCase() {
@Mock private lateinit var qsFrame: View
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/PulsingGestureListenerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/PulsingGestureListenerTest.kt
index 3900def..effd28ed 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/PulsingGestureListenerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/PulsingGestureListenerTest.kt
@@ -20,9 +20,9 @@
import android.os.PowerManager
import android.provider.Settings.Secure.DOZE_DOUBLE_TAP_GESTURE
import android.provider.Settings.Secure.DOZE_TAP_SCREEN_GESTURE
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
import android.view.MotionEvent
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.dock.DockManager
@@ -49,7 +49,7 @@
import org.mockito.MockitoAnnotations
import org.mockito.Mockito.`when` as whenever
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@RunWithLooper(setAsMainLooper = true)
@SmallTest
class PulsingGestureListenerTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/QsBatteryModeControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/QsBatteryModeControllerTest.kt
index 2cd740d..f38bf13 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/QsBatteryModeControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/QsBatteryModeControllerTest.kt
@@ -3,8 +3,8 @@
import android.content.Context
import android.content.res.Resources
import android.graphics.Rect
-import android.testing.AndroidTestingRunner
import android.view.DisplayCutout
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.res.R
import com.android.systemui.SysuiTestCase
@@ -21,7 +21,7 @@
import org.mockito.junit.MockitoJUnit
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class QsBatteryModeControllerTest : SysuiTestCase() {
private companion object {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerImplTest.java
index ad4b4fd..9a6423d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerImplTest.java
@@ -36,10 +36,10 @@
import static org.mockito.Mockito.when;
import android.platform.test.annotations.EnableFlags;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.MotionEvent;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.plugins.qs.QS;
@@ -53,7 +53,7 @@
import java.util.List;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
public class QuickSettingsControllerImplTest extends QuickSettingsControllerImplBaseTest {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerImplWithCoroutinesTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerImplWithCoroutinesTest.kt
index dfd7a71..46961d4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerImplWithCoroutinesTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerImplWithCoroutinesTest.kt
@@ -17,6 +17,7 @@
package com.android.systemui.shade
import android.app.StatusBarManager
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.statusbar.disableflags.data.model.DisableFlagsModel
import com.google.common.truth.Truth.assertThat
@@ -25,9 +26,11 @@
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Test
+import org.junit.runner.RunWith
@SmallTest
@OptIn(ExperimentalCoroutinesApi::class)
+@RunWith(AndroidJUnit4::class)
class QuickSettingsControllerImplWithCoroutinesTest : QuickSettingsControllerImplBaseTest() {
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeControllerImplTest.kt
index 6bdd3ef..0217238 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeControllerImplTest.kt
@@ -16,10 +16,10 @@
package com.android.systemui.shade
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
import android.view.Display
import android.view.WindowManager
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.internal.statusbar.IStatusBarService
import com.android.systemui.SysuiTestCase
@@ -59,7 +59,7 @@
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@RunWithLooper(setAsMainLooper = true)
@SmallTest
class ShadeControllerImplTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeExpansionStateManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeExpansionStateManagerTest.kt
index 89ae42f..4734ede 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeExpansionStateManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeExpansionStateManagerTest.kt
@@ -16,13 +16,16 @@
package com.android.systemui.shade
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
+import org.junit.runner.RunWith
@SmallTest
+@RunWith(AndroidJUnit4::class)
class ShadeExpansionStateManagerTest : SysuiTestCase() {
private lateinit var shadeExpansionStateManager: ShadeExpansionStateManager
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/carrier/CellSignalStateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/carrier/CellSignalStateTest.kt
index 7a9ef62..c669959 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/carrier/CellSignalStateTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/carrier/CellSignalStateTest.kt
@@ -16,7 +16,7 @@
package com.android.systemui.shade.carrier
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import org.junit.Assert.assertNotSame
@@ -24,7 +24,7 @@
import org.junit.Test
import org.junit.runner.RunWith
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
class CellSignalStateTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/carrier/ShadeCarrierTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/carrier/ShadeCarrierTest.java
index a42121a..1a2531a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/carrier/ShadeCarrierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/carrier/ShadeCarrierTest.java
@@ -21,13 +21,13 @@
import static org.junit.Assert.assertTrue;
import android.content.Context;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.settingslib.mobile.TelephonyIcons;
@@ -38,7 +38,7 @@
import org.junit.Test;
import org.junit.runner.RunWith;
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper
@SmallTest
public class ShadeCarrierTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/transition/ScrimShadeTransitionControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/transition/ScrimShadeTransitionControllerTest.kt
index 7c33648..10c017b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/transition/ScrimShadeTransitionControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/transition/ScrimShadeTransitionControllerTest.kt
@@ -1,6 +1,6 @@
package com.android.systemui.shade.transition
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.deviceentry.data.repository.FakeDeviceEntryRepository
@@ -30,7 +30,7 @@
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
class ScrimShadeTransitionControllerTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shadow/DoubleShadowTextClockTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shadow/DoubleShadowTextClockTest.kt
index 4679a58..89a3d5b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shadow/DoubleShadowTextClockTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shadow/DoubleShadowTextClockTest.kt
@@ -20,8 +20,8 @@
import android.content.res.Resources
import android.content.res.TypedArray
import android.platform.test.annotations.PlatinumTest
-import android.testing.AndroidTestingRunner
import android.util.AttributeSet
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.shared.R
@@ -39,7 +39,7 @@
@PlatinumTest(focusArea = "sysui")
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class DoubleShadowTextClockTest : SysuiTestCase() {
@get:Rule val mockito: MockitoRule = MockitoJUnit.rule()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/animation/DisableSubpixelTextTransitionListenerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shared/animation/DisableSubpixelTextTransitionListenerTest.kt
index fc230e3..5d8f868 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/animation/DisableSubpixelTextTransitionListenerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/animation/DisableSubpixelTextTransitionListenerTest.kt
@@ -17,9 +17,9 @@
package com.android.systemui.shared.animation
import android.graphics.Paint
-import android.testing.AndroidTestingRunner
import android.widget.FrameLayout
import android.widget.TextView
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.google.common.truth.Truth.assertThat
@@ -28,7 +28,7 @@
import org.junit.runner.RunWith
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class DisableSubpixelTextTransitionListenerTest : SysuiTestCase() {
private lateinit var disableSubpixelTextTransitionListener:
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/animation/UnfoldConstantTranslateAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shared/animation/UnfoldConstantTranslateAnimatorTest.kt
index 293dc04..3a53a5a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/animation/UnfoldConstantTranslateAnimatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/animation/UnfoldConstantTranslateAnimatorTest.kt
@@ -14,9 +14,9 @@
*/
package com.android.systemui.shared.animation
-import android.testing.AndroidTestingRunner
import android.view.View
import android.view.ViewGroup
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.shared.animation.UnfoldConstantTranslateAnimator.Direction
@@ -34,7 +34,7 @@
import org.mockito.MockitoAnnotations
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class UnfoldConstantTranslateAnimatorTest : SysuiTestCase() {
private val progressProvider = FakeUnfoldTransitionProvider()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/animation/UnfoldMoveFromCenterAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shared/animation/UnfoldMoveFromCenterAnimatorTest.kt
index 3cb48d9..fbaddfa 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/animation/UnfoldMoveFromCenterAnimatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/animation/UnfoldMoveFromCenterAnimatorTest.kt
@@ -15,8 +15,8 @@
package com.android.systemui.shared.animation
import android.graphics.Point
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
-import android.testing.AndroidTestingRunner
import android.view.Display
import android.view.Surface.ROTATION_0
import android.view.Surface.ROTATION_90
@@ -36,7 +36,7 @@
import org.mockito.junit.MockitoJUnit
import org.mockito.Mockito.`when` as whenever
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
class UnfoldMoveFromCenterAnimatorTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/AnimatableClockViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/AnimatableClockViewTest.kt
index 7b0cd19..e076418 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/AnimatableClockViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/AnimatableClockViewTest.kt
@@ -16,8 +16,8 @@
package com.android.systemui.shared.clocks
-import android.testing.AndroidTestingRunner
import android.view.LayoutInflater
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.app.animation.Interpolators
import com.android.systemui.customization.R
@@ -34,7 +34,7 @@
import org.mockito.Mockito.verifyNoMoreInteractions
import org.mockito.junit.MockitoJUnit
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
class AnimatableClockViewTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt
index 74d0173..2f52248 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt
@@ -19,7 +19,7 @@
import android.content.ContentResolver
import android.content.Context
import android.graphics.drawable.Drawable
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.flags.FakeFeatureFlags
@@ -55,7 +55,7 @@
import org.mockito.Mockito.`when` as whenever
import org.mockito.junit.MockitoJUnit
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
class ClockRegistryTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/DefaultClockProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/DefaultClockProviderTest.kt
index e0e8d1f..2522ed7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/DefaultClockProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/DefaultClockProviderTest.kt
@@ -19,10 +19,10 @@
import android.content.res.Resources
import android.graphics.Color
import android.graphics.drawable.Drawable
-import android.testing.AndroidTestingRunner
import android.util.TypedValue
import android.view.LayoutInflater
import android.widget.FrameLayout
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.customization.R
@@ -53,7 +53,7 @@
private fun DefaultClockProvider.createClock(id: ClockId): DefaultClockController =
createClock(ClockSettings(id, null)) as DefaultClockController
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
class DefaultClockProviderTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/condition/CombinedConditionTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shared/condition/CombinedConditionTest.kt
index 1a0e932..8418598 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/condition/CombinedConditionTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/condition/CombinedConditionTest.kt
@@ -16,7 +16,7 @@
package com.android.systemui.shared.condition
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.shared.condition.Condition.START_EAGERLY
@@ -32,7 +32,7 @@
import org.junit.runner.RunWith
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class CombinedConditionTest : SysuiTestCase() {
class FakeCondition
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/condition/ConditionExtensionsTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shared/condition/ConditionExtensionsTest.kt
index 0a8210d..83fb14a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/condition/ConditionExtensionsTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/condition/ConditionExtensionsTest.kt
@@ -1,6 +1,6 @@
package com.android.systemui.shared.condition
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.google.common.truth.Truth.assertThat
@@ -19,7 +19,7 @@
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class ConditionExtensionsTest : SysuiTestCase() {
private lateinit var testScope: TestScope
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/condition/ConditionMonitorTest.java b/packages/SystemUI/tests/src/com/android/systemui/shared/condition/ConditionMonitorTest.java
index 65ca0a2..267f22b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/condition/ConditionMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/condition/ConditionMonitorTest.java
@@ -27,8 +27,8 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import android.testing.AndroidTestingRunner;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -51,7 +51,7 @@
import java.util.HashSet;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
public class ConditionMonitorTest extends SysuiTestCase {
private FakeCondition mCondition1;
private FakeCondition mCondition2;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/condition/ConditionTest.java b/packages/SystemUI/tests/src/com/android/systemui/shared/condition/ConditionTest.java
index cec5d0a..a224843 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/condition/ConditionTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/condition/ConditionTest.java
@@ -25,8 +25,8 @@
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
-import android.testing.AndroidTestingRunner;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -40,7 +40,7 @@
import org.mockito.MockitoAnnotations;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
public class ConditionTest extends SysuiTestCase {
@Mock
CoroutineScope mScope;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/navigationbar/RegionSamplingHelperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shared/navigationbar/RegionSamplingHelperTest.kt
index 5fc09c7..2a6754c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/navigationbar/RegionSamplingHelperTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/navigationbar/RegionSamplingHelperTest.kt
@@ -17,12 +17,12 @@
package com.android.systemui.shared.navigationbar
import android.graphics.Rect
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
import android.view.SurfaceControl
import android.view.View
import android.view.ViewRootImpl
import androidx.concurrent.futures.DirectExecutor
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.util.concurrency.FakeExecutor
@@ -43,7 +43,7 @@
import org.mockito.Mockito.`when` as whenever
import org.mockito.junit.MockitoJUnit
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
@RunWithLooper
class RegionSamplingHelperTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/notifications/data/repository/NotificationSettingsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shared/notifications/data/repository/NotificationSettingsRepositoryTest.kt
index 0dd988d..8bfb07b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/notifications/data/repository/NotificationSettingsRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/notifications/data/repository/NotificationSettingsRepositoryTest.kt
@@ -17,6 +17,7 @@
package com.android.systemui.shared.notifications.data.repository
import android.provider.Settings
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
@@ -28,10 +29,9 @@
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
@SmallTest
-@RunWith(JUnit4::class)
+@RunWith(AndroidJUnit4::class)
class NotificationSettingsRepositoryTest : SysuiTestCase() {
private lateinit var underTest: NotificationSettingsRepository
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginManagerTest.java
index 40c84d6..c721ceb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginManagerTest.java
@@ -28,9 +28,9 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.net.Uri;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper.RunWithLooper;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
@@ -55,7 +55,7 @@
import java.util.List;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@RunWithLooper
public class PluginManagerTest extends SysuiTestCase {
private static final String PRIVILEGED_PACKAGE = "com.android.systemui";
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/VersionInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/VersionInfoTest.java
index 711187b..15fdc7c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/VersionInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/VersionInfoTest.java
@@ -17,6 +17,7 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -29,8 +30,10 @@
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
+import org.junit.runner.RunWith;
@SmallTest
+@RunWith(AndroidJUnit4.class)
public class VersionInfoTest extends SysuiTestCase {
@Rule
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/regionsampling/RegionSamplerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shared/regionsampling/RegionSamplerTest.kt
index 1031621..7fc845c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/regionsampling/RegionSamplerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/regionsampling/RegionSamplerTest.kt
@@ -4,8 +4,8 @@
import android.app.WallpaperManager
import android.graphics.Color
import android.graphics.RectF
-import android.testing.AndroidTestingRunner
import android.view.View
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.util.mockito.any
@@ -28,7 +28,7 @@
import org.mockito.Mockito.`when` as whenever
import org.mockito.junit.MockitoJUnit
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
class RegionSamplerTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/rotation/RotationButtonControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shared/rotation/RotationButtonControllerTest.kt
index ee3d870..5a4ef05 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/rotation/RotationButtonControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/rotation/RotationButtonControllerTest.kt
@@ -15,11 +15,11 @@
*/
package com.android.systemui.shared.rotation
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
import android.view.Display
import android.view.WindowInsetsController
import android.view.WindowManagerPolicyConstants
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.google.common.truth.Truth.assertThat
@@ -27,7 +27,7 @@
import org.junit.Test
import org.junit.runner.RunWith
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
@RunWithLooper
class RotationButtonControllerTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/system/UncaughtExceptionPreHandlerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shared/system/UncaughtExceptionPreHandlerTest.kt
index b761647..d67ce30 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/system/UncaughtExceptionPreHandlerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/system/UncaughtExceptionPreHandlerTest.kt
@@ -1,5 +1,6 @@
package com.android.systemui.shared.system
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.google.common.truth.Truth.assertThat
@@ -8,6 +9,7 @@
import org.junit.Before
import org.junit.Ignore
import org.junit.Test
+import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.Mockito.any
import org.mockito.Mockito.only
@@ -16,6 +18,7 @@
import org.mockito.MockitoAnnotations
@SmallTest
+@RunWith(AndroidJUnit4::class)
class UncaughtExceptionPreHandlerTest : SysuiTestCase() {
private lateinit var preHandlerManager: UncaughtExceptionPreHandlerManager
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/BlurUtilsTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/BlurUtilsTest.kt
index e9676c8..d0ba629 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/BlurUtilsTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/BlurUtilsTest.kt
@@ -20,11 +20,13 @@
import android.view.CrossWindowBlurListeners
import android.view.SurfaceControl
import android.view.ViewRootImpl
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.dump.DumpManager
import org.junit.Before
import org.junit.Test
+import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.Mockito.`when`
import org.mockito.Mockito.any
@@ -37,6 +39,7 @@
import org.mockito.MockitoAnnotations
@SmallTest
+@RunWith(AndroidJUnit4::class)
class BlurUtilsTest : SysuiTestCase() {
@Mock lateinit var resources: Resources
@@ -117,4 +120,4 @@
return transaction
}
}
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
index 5da3a56..9df46e5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
@@ -42,6 +42,7 @@
import android.view.WindowInsetsController.Behavior;
import android.view.accessibility.Flags;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.internal.statusbar.LetterboxDetails;
@@ -54,8 +55,10 @@
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
+import org.junit.runner.RunWith;
@SmallTest
+@RunWith(AndroidJUnit4.class)
public class CommandQueueTest extends SysuiTestCase {
private static final LetterboxDetails[] TEST_LETTERBOX_DETAILS = new LetterboxDetails[] {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationUiAdjustmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationUiAdjustmentTest.java
index 3b85dba..5f9c9df 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationUiAdjustmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationUiAdjustmentTest.java
@@ -23,18 +23,21 @@
import android.content.Intent;
import android.graphics.drawable.Icon;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.internal.R;
import com.android.systemui.SysuiTestCase;
import org.junit.Test;
+import org.junit.runner.RunWith;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@SmallTest
+@RunWith(AndroidJUnit4.class)
public class NotificationUiAdjustmentTest extends SysuiTestCase {
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/OperatorNameViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/OperatorNameViewControllerTest.kt
index 9c59f9b..396d017 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/OperatorNameViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/OperatorNameViewControllerTest.kt
@@ -20,6 +20,7 @@
import android.telephony.SubscriptionInfo
import android.telephony.TelephonyManager
import android.telephony.telephonyManager
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.keyguard.keyguardUpdateMonitor
import com.android.systemui.SysuiTestCase
@@ -44,11 +45,13 @@
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
+import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.MockitoAnnotations
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
+@RunWith(AndroidJUnit4::class)
class OperatorNameViewControllerTest : SysuiTestCase() {
private lateinit var underTest: OperatorNameViewController
private lateinit var airplaneModeInteractor: AirplaneModeInteractor
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModelTest.kt
index 6cac30a..3606b1b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModelTest.kt
@@ -26,6 +26,7 @@
import com.android.systemui.kosmos.testScope
import com.android.systemui.plugins.activityStarter
import com.android.systemui.res.R
+import com.android.systemui.statusbar.chips.ui.model.ColorsModel
import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel
import com.android.systemui.statusbar.chips.ui.view.ChipBackgroundContainer
import com.android.systemui.statusbar.phone.ongoingcall.data.repository.ongoingCallRepository
@@ -95,7 +96,7 @@
}
@Test
- fun chip_inCall_iconIsPhone() =
+ fun chip_iconIsPhone() =
testScope.runTest {
val latest by collectLastValue(underTest.chip)
@@ -106,6 +107,17 @@
}
@Test
+ fun chip_colorsAreThemed() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.chip)
+
+ repo.setOngoingCallState(OngoingCallModel.InCall(startTimeMs = 1000, intent = null))
+
+ assertThat((latest as OngoingActivityChipModel.Shown).colors)
+ .isEqualTo(ColorsModel.Themed)
+ }
+
+ @Test
fun chip_resetsCorrectly() =
testScope.runTest {
val latest by collectLastValue(underTest.chip)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/casttootherdevice/ui/viewmodel/CastToOtherDeviceChipViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/casttootherdevice/ui/viewmodel/CastToOtherDeviceChipViewModelTest.kt
index 93d781f..d7935e5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/casttootherdevice/ui/viewmodel/CastToOtherDeviceChipViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/casttootherdevice/ui/viewmodel/CastToOtherDeviceChipViewModelTest.kt
@@ -33,6 +33,7 @@
import com.android.systemui.statusbar.chips.mediaprojection.domain.interactor.MediaProjectionChipInteractorTest.Companion.CAST_TO_OTHER_DEVICES_PACKAGE
import com.android.systemui.statusbar.chips.mediaprojection.domain.interactor.MediaProjectionChipInteractorTest.Companion.NORMAL_PACKAGE
import com.android.systemui.statusbar.chips.mediaprojection.domain.interactor.MediaProjectionChipInteractorTest.Companion.setUpPackageManagerForMediaProjection
+import com.android.systemui.statusbar.chips.ui.model.ColorsModel
import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel
import com.android.systemui.statusbar.chips.ui.view.ChipBackgroundContainer
import com.android.systemui.statusbar.phone.SystemUIDialog
@@ -119,6 +120,17 @@
}
@Test
+ fun chip_colorsAreRed() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.chip)
+
+ mediaProjectionRepo.mediaProjectionState.value =
+ MediaProjectionState.Projecting.EntireScreen(CAST_TO_OTHER_DEVICES_PACKAGE)
+
+ assertThat((latest as OngoingActivityChipModel.Shown).colors).isEqualTo(ColorsModel.Red)
+ }
+
+ @Test
fun chip_singleTaskState_normalPackage_isHidden() =
testScope.runTest {
val latest by collectLastValue(underTest.chip)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/screenrecord/ui/viewmodel/ScreenRecordChipViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/screenrecord/ui/viewmodel/ScreenRecordChipViewModelTest.kt
index 45044f7..fdf0e5d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/screenrecord/ui/viewmodel/ScreenRecordChipViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/screenrecord/ui/viewmodel/ScreenRecordChipViewModelTest.kt
@@ -32,6 +32,7 @@
import com.android.systemui.screenrecord.data.model.ScreenRecordModel
import com.android.systemui.screenrecord.data.repository.screenRecordRepository
import com.android.systemui.statusbar.chips.screenrecord.ui.view.EndScreenRecordingDialogDelegate
+import com.android.systemui.statusbar.chips.ui.model.ColorsModel
import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel
import com.android.systemui.statusbar.chips.ui.view.ChipBackgroundContainer
import com.android.systemui.statusbar.phone.SystemUIDialog
@@ -109,6 +110,16 @@
}
@Test
+ fun chip_colorsAreRed() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.chip)
+
+ screenRecordRepo.screenRecordState.value = ScreenRecordModel.Recording
+
+ assertThat((latest as OngoingActivityChipModel.Shown).colors).isEqualTo(ColorsModel.Red)
+ }
+
+ @Test
fun chip_timeResetsOnEachNewRecording() =
testScope.runTest {
val latest by collectLastValue(underTest.chip)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/sharetoapp/ui/viewmodel/ShareToAppChipViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/sharetoapp/ui/viewmodel/ShareToAppChipViewModelTest.kt
index 9aef526..8ea3f4a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/sharetoapp/ui/viewmodel/ShareToAppChipViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/sharetoapp/ui/viewmodel/ShareToAppChipViewModelTest.kt
@@ -33,6 +33,7 @@
import com.android.systemui.statusbar.chips.mediaprojection.domain.interactor.MediaProjectionChipInteractorTest.Companion.NORMAL_PACKAGE
import com.android.systemui.statusbar.chips.mediaprojection.domain.interactor.MediaProjectionChipInteractorTest.Companion.setUpPackageManagerForMediaProjection
import com.android.systemui.statusbar.chips.sharetoapp.ui.view.EndShareToAppDialogDelegate
+import com.android.systemui.statusbar.chips.ui.model.ColorsModel
import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel
import com.android.systemui.statusbar.chips.ui.view.ChipBackgroundContainer
import com.android.systemui.statusbar.phone.SystemUIDialog
@@ -144,6 +145,17 @@
}
@Test
+ fun chip_colorsAreRed() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.chip)
+
+ mediaProjectionRepo.mediaProjectionState.value =
+ MediaProjectionState.Projecting.EntireScreen(NORMAL_PACKAGE)
+
+ assertThat((latest as OngoingActivityChipModel.Shown).colors).isEqualTo(ColorsModel.Red)
+ }
+
+ @Test
fun chip_timeResetsOnEachNewShare() =
testScope.runTest {
val latest by collectLastValue(underTest.chip)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/ui/view/ChipBackgroundContainerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/ui/view/ChipBackgroundContainerTest.kt
index 7d2b463..5fbdfbf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/ui/view/ChipBackgroundContainerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/ui/view/ChipBackgroundContainerTest.kt
@@ -16,10 +16,10 @@
package com.android.systemui.statusbar.chips.ui.view
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.view.LayoutInflater
import android.view.View
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.res.R
@@ -29,7 +29,7 @@
import org.junit.runner.RunWith
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@TestableLooper.RunWithLooper
class ChipBackgroundContainerTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/ui/view/ChipChronometerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/ui/view/ChipChronometerTest.kt
index b8d4e47..6f771175 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/ui/view/ChipChronometerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/ui/view/ChipChronometerTest.kt
@@ -16,10 +16,10 @@
package com.android.systemui.statusbar.chips.ui.view
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.view.LayoutInflater
import android.view.View
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.res.R
@@ -36,7 +36,7 @@
private const val XL_TEXT = "00:0000"
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@TestableLooper.RunWithLooper
class ChipChronometerTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelTest.kt
index a7b1411f..912a10a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.chips.ui.viewmodel
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.common.shared.model.Icon
@@ -38,8 +39,10 @@
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
+import org.junit.runner.RunWith
@SmallTest
+@RunWith(AndroidJUnit4::class)
class OngoingActivityChipsViewModelTest : SysuiTestCase() {
private val kosmos = Kosmos().also { it.testCase = this }
private val testScope = kosmos.testScope
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/commandline/CommandParserTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/commandline/CommandParserTest.kt
index cfbe8e3..673cf59 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/commandline/CommandParserTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/commandline/CommandParserTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.commandline
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.google.common.truth.Truth.assertThat
@@ -24,8 +25,10 @@
import org.junit.Assert.assertThrows
import org.junit.Assert.assertTrue
import org.junit.Test
+import org.junit.runner.RunWith
@SmallTest
+@RunWith(AndroidJUnit4::class)
class CommandParserTest : SysuiTestCase() {
private val parser = CommandParser()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/commandline/ParametersTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/commandline/ParametersTest.kt
index e391d6b..83811cd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/commandline/ParametersTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/commandline/ParametersTest.kt
@@ -1,5 +1,6 @@
package com.android.systemui.statusbar.commandline
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.google.common.truth.Truth.assertThat
@@ -7,8 +8,10 @@
import org.junit.Assert.assertThrows
import org.junit.Assert.assertTrue
import org.junit.Test
+import org.junit.runner.RunWith
@SmallTest
+@RunWith(AndroidJUnit4::class)
class ParametersTest : SysuiTestCase() {
@Test
fun singleArgOptional_returnsNullBeforeParse() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/commandline/ParseableCommandTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/commandline/ParseableCommandTest.kt
index 86548d0..1a7c8a3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/commandline/ParseableCommandTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/commandline/ParseableCommandTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.commandline
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.google.common.truth.Truth.assertThat
@@ -24,10 +25,12 @@
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Test
+import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.MockitoAnnotations
@SmallTest
+@RunWith(AndroidJUnit4::class)
class ParseableCommandTest : SysuiTestCase() {
@Mock private lateinit var pw: PrintWriter
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/commandline/ValueParserTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/commandline/ValueParserTest.kt
index 759f0bc..8cf7473 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/commandline/ValueParserTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/commandline/ValueParserTest.kt
@@ -1,13 +1,16 @@
package com.android.systemui.statusbar.commandline
import android.graphics.Rect
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.google.common.truth.Truth.assertThat
import org.junit.Assert.assertTrue
import org.junit.Test
+import org.junit.runner.RunWith
@SmallTest
+@RunWith(AndroidJUnit4::class)
class ValueParserTest : SysuiTestCase() {
@Test
fun parseString() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/ui/MobileContextProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/ui/MobileContextProviderTest.kt
index 0fdda62..ca90f74 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/ui/MobileContextProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/ui/MobileContextProviderTest.kt
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.connectivity.ui
import android.telephony.SubscriptionInfo
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.demomode.DemoModeController
@@ -28,12 +29,14 @@
import com.google.common.truth.Truth.assertThat
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.Mockito.`when` as whenever
import org.mockito.MockitoAnnotations
@SmallTest
+@RunWith(AndroidJUnit4::class)
class MobileContextProviderTest : SysuiTestCase() {
@Mock private lateinit var networkController: NetworkController
@Mock private lateinit var dumpManager: DumpManager
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/data/repository/KeyguardStatusBarRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/data/repository/KeyguardStatusBarRepositoryImplTest.kt
index b1c994c..7c98037 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/data/repository/KeyguardStatusBarRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/data/repository/KeyguardStatusBarRepositoryImplTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.data.repository
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.internal.R
import com.android.systemui.SysuiTestCase
@@ -29,9 +30,11 @@
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runTest
import org.junit.Test
+import org.junit.runner.RunWith
import org.mockito.Mockito.verify
@SmallTest
+@RunWith(AndroidJUnit4::class)
class KeyguardStatusBarRepositoryImplTest : SysuiTestCase() {
private val testScope = TestScope()
private val configurationController = mock<ConfigurationController>()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/data/repository/StatusBarModeRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/data/repository/StatusBarModeRepositoryImplTest.kt
index 4b250b2..7f981ee 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/data/repository/StatusBarModeRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/data/repository/StatusBarModeRepositoryImplTest.kt
@@ -23,6 +23,7 @@
import android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS
import android.view.WindowInsetsController.APPEARANCE_OPAQUE_STATUS_BARS
import android.view.WindowInsetsController.APPEARANCE_SEMI_TRANSPARENT_STATUS_BARS
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.internal.statusbar.LetterboxDetails
import com.android.internal.view.AppearanceRegion
@@ -48,9 +49,11 @@
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
+import org.junit.runner.RunWith
import org.mockito.Mockito.verify
@SmallTest
+@RunWith(AndroidJUnit4::class)
class StatusBarModeRepositoryImplTest : SysuiTestCase() {
private val testScope = TestScope()
private val commandQueue = mock<CommandQueue>()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/disableflags/DisableFlagsLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/disableflags/DisableFlagsLoggerTest.kt
index f1c7956..fffcbb6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/disableflags/DisableFlagsLoggerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/disableflags/DisableFlagsLoggerTest.kt
@@ -16,13 +16,16 @@
package com.android.systemui.statusbar.disableflags
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.google.common.truth.Truth.assertThat
import org.junit.Assert.assertThrows
import org.junit.Test
+import org.junit.runner.RunWith
@SmallTest
+@RunWith(AndroidJUnit4::class)
class DisableFlagsLoggerTest : SysuiTestCase() {
private val disable1Flags = listOf(
DisableFlagsLogger.DisableFlag(0b100, 'A', 'a'),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/disableflags/DisableStateTrackerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/disableflags/DisableStateTrackerTest.kt
index 215afb2..cf78c71 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/disableflags/DisableStateTrackerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/disableflags/DisableStateTrackerTest.kt
@@ -24,17 +24,20 @@
import android.app.StatusBarManager.DISABLE_NAVIGATION
import android.app.StatusBarManager.DISABLE_NOTIFICATION_ICONS
import android.app.StatusBarManager.DISABLE_NOTIFICATION_TICKER
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.statusbar.CommandQueue
import com.google.common.truth.Truth.assertThat
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(AndroidJUnit4::class)
class DisableStateTrackerTest : SysuiTestCase() {
private lateinit var underTest: DisableStateTracker
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/disableflags/data/repository/DisableFlagsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/disableflags/data/repository/DisableFlagsRepositoryTest.kt
index 31e1fef..d2dfc92 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/disableflags/data/repository/DisableFlagsRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/disableflags/data/repository/DisableFlagsRepositoryTest.kt
@@ -21,6 +21,7 @@
import android.app.StatusBarManager.DISABLE_NONE
import android.app.StatusBarManager.DISABLE_NOTIFICATION_ALERTS
import android.content.res.Configuration
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.res.R
import com.android.systemui.SysuiTestCase
@@ -42,10 +43,12 @@
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
+import org.junit.runner.RunWith
import org.mockito.Mockito.verify
@SmallTest
@OptIn(ExperimentalCoroutinesApi::class)
+@RunWith(AndroidJUnit4::class)
class DisableFlagsRepositoryTest : SysuiTestCase() {
private lateinit var underTest: DisableFlagsRepository
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt
index b944d72..7a8533e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt
@@ -35,6 +35,7 @@
import android.testing.TestableLooper.RunWithLooper
import android.view.View
import android.widget.FrameLayout
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.systemui.SysuiTestCase
@@ -69,6 +70,7 @@
import com.android.systemui.util.time.FakeSystemClock
import org.junit.Before
import org.junit.Test
+import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
import org.mockito.Captor
import org.mockito.Mock
@@ -86,6 +88,7 @@
@SmallTest
@RunWithLooper(setAsMainLooper = true)
+@RunWith(AndroidJUnit4::class)
class LockscreenSmartspaceControllerTest : SysuiTestCase() {
companion object {
const val SMARTSPACE_TIME_TOO_EARLY = 1000L
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinatorTest.kt
index b161f84..0505727 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinatorTest.kt
@@ -23,6 +23,7 @@
import android.platform.test.annotations.DisableFlags
import android.platform.test.annotations.EnableFlags
import android.service.notification.StatusBarNotification
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.server.notification.Flags.FLAG_SCREENSHARE_NOTIFICATION_HIDING
@@ -54,11 +55,13 @@
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Test
+import org.junit.runner.RunWith
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
import org.mockito.Mockito.`when` as whenever
@SmallTest
+@RunWith(AndroidJUnit4::class)
class SensitiveContentCoordinatorTest : SysuiTestCase() {
val dynamicPrivacyController: DynamicPrivacyController = mock()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/SmartspaceDedupingCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/SmartspaceDedupingCoordinatorTest.kt
index 8272f5a..ef2a2aa 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/SmartspaceDedupingCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/SmartspaceDedupingCoordinatorTest.kt
@@ -19,6 +19,7 @@
import android.app.smartspace.SmartspaceTarget
import android.content.ComponentName
import android.os.UserHandle
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.plugins.BcSmartspaceDataPlugin.SmartspaceTargetListener
@@ -43,6 +44,7 @@
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Test
+import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.Mockito.clearInvocations
import org.mockito.Mockito.never
@@ -51,6 +53,7 @@
import org.mockito.MockitoAnnotations
@SmallTest
+@RunWith(AndroidJUnit4::class)
class SmartspaceDedupingCoordinatorTest : SysuiTestCase() {
@Mock
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilderTest.kt
index 11996fe..99bd4fc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilderTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.notification.collection.render
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.log.logcatLogBuffer
@@ -37,10 +38,12 @@
import com.android.systemui.util.mockito.mock
import org.junit.Before
import org.junit.Test
+import org.junit.runner.RunWith
import org.mockito.Mockito
import org.mockito.Mockito.`when` as whenever
@SmallTest
+@RunWith(AndroidJUnit4::class)
class NodeSpecBuilderTest : SysuiTestCase() {
private val mediaContainerController: MediaContainerController = mock()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/RenderStageManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/RenderStageManagerTest.kt
index 70d309b..ca75ca6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/RenderStageManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/RenderStageManagerTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.notification.collection.render
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.statusbar.notification.collection.GroupEntry
@@ -32,6 +33,7 @@
import com.android.systemui.util.mockito.withArgCaptor
import org.junit.Before
import org.junit.Test
+import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.Mockito.inOrder
import org.mockito.Mockito.never
@@ -42,6 +44,7 @@
import org.mockito.MockitoAnnotations
@SmallTest
+@RunWith(AndroidJUnit4::class)
class RenderStageManagerTest : SysuiTestCase() {
@Mock private lateinit var shadeListBuilder: ShadeListBuilder
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationAlertsInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationAlertsInteractorTest.kt
index b775079..79ff4be 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationAlertsInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationAlertsInteractorTest.kt
@@ -15,6 +15,7 @@
package com.android.systemui.statusbar.notification.domain.interactor
import android.app.StatusBarManager
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysUITestComponent
import com.android.systemui.SysUITestModule
@@ -26,8 +27,10 @@
import dagger.BindsInstance
import dagger.Component
import org.junit.Test
+import org.junit.runner.RunWith
@SmallTest
+@RunWith(AndroidJUnit4::class)
class NotificationAlertsInteractorTest : SysuiTestCase() {
@Component(modules = [SysUITestModule::class])
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationLaunchAnimationInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationLaunchAnimationInteractorTest.kt
index a0faab5..982b7b1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationLaunchAnimationInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationLaunchAnimationInteractorTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.notification.domain.interactor
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
@@ -23,8 +24,10 @@
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.test.runTest
import org.junit.Test
+import org.junit.runner.RunWith
@SmallTest
+@RunWith(AndroidJUnit4::class)
class NotificationLaunchAnimationInteractorTest : SysuiTestCase() {
private val repository = NotificationLaunchAnimationRepository()
private val underTest = NotificationLaunchAnimationInteractor(repository)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationsKeyguardInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationsKeyguardInteractorTest.kt
index 3593f5b..133a114 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationsKeyguardInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationsKeyguardInteractorTest.kt
@@ -13,6 +13,7 @@
*/
package com.android.systemui.statusbar.notification.domain.interactor
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysUITestComponent
import com.android.systemui.SysUITestModule
@@ -25,8 +26,10 @@
import dagger.BindsInstance
import dagger.Component
import org.junit.Test
+import org.junit.runner.RunWith
@SmallTest
+@RunWith(AndroidJUnit4::class)
class NotificationsKeyguardInteractorTest : SysuiTestCase() {
@SysUISingleton
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/RenderNotificationsListInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/RenderNotificationsListInteractorTest.kt
index 334776c..277b887 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/RenderNotificationsListInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/RenderNotificationsListInteractorTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.notification.domain.interactor
import android.service.notification.StatusBarNotification
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
@@ -31,8 +32,10 @@
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runTest
import org.junit.Test
+import org.junit.runner.RunWith
@SmallTest
+@RunWith(AndroidJUnit4::class)
class RenderNotificationsListInteractorTest : SysuiTestCase() {
private val backgroundDispatcher = StandardTestDispatcher()
private val testScope = TestScope(backgroundDispatcher)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
index 7304bd6..0766afc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
@@ -793,6 +793,73 @@
}
@Test
+ public void isExpanded_onKeyguard_allowOnKeyguardExpanded() throws Exception {
+ // GIVEN
+ final ExpandableNotificationRow row = mNotificationTestHelper.createRow();
+ row.setOnKeyguard(true);
+ row.setUserExpanded(true);
+
+ // THEN
+ assertThat(row.isExpanded(/*allowOnKeyguard =*/ true)).isTrue();
+ }
+ @Test
+ public void isExpanded_onKeyguard_notAllowOnKeyguardNotExpanded() throws Exception {
+ // GIVEN
+ final ExpandableNotificationRow row = mNotificationTestHelper.createRow();
+ row.setOnKeyguard(true);
+ row.setUserExpanded(true);
+
+ // THEN
+ assertThat(row.isExpanded(/*allowOnKeyguard =*/ false)).isFalse();
+ }
+
+ @Test
+ public void isExpanded_systemExpanded_expanded() throws Exception {
+ // GIVEN
+ final ExpandableNotificationRow row = mNotificationTestHelper.createRow();
+ row.setOnKeyguard(false);
+ row.setSystemExpanded(true);
+
+ // THEN
+ assertThat(row.isExpanded()).isTrue();
+ }
+
+ @Test
+ public void isExpanded_systemChildExpanded_expanded() throws Exception {
+ // GIVEN
+ final ExpandableNotificationRow row = mNotificationTestHelper.createRow();
+ row.setOnKeyguard(false);
+ row.setSystemChildExpanded(true);
+
+ // THEN
+ assertThat(row.isExpanded()).isTrue();
+ }
+
+ @Test
+ public void isExpanded_userExpanded_expanded() throws Exception {
+ // GIVEN
+ final ExpandableNotificationRow row = mNotificationTestHelper.createRow();
+ row.setOnKeyguard(false);
+ row.setSystemExpanded(true);
+ row.setUserExpanded(true);
+
+ // THEN
+ assertThat(row.isExpanded()).isTrue();
+ }
+
+ @Test
+ public void isExpanded_userExpandedFalse_notExpanded() throws Exception {
+ // GIVEN
+ final ExpandableNotificationRow row = mNotificationTestHelper.createRow();
+ row.setOnKeyguard(false);
+ row.setSystemExpanded(true);
+ row.setUserExpanded(false);
+
+ // THEN
+ assertThat(row.isExpanded()).isFalse();
+ }
+
+ @Test
public void onDisappearAnimationFinished_shouldSetFalse_headsUpAnimatingAway()
throws Exception {
final ExpandableNotificationRow row = mNotificationTestHelper.createRow();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/DisplaySwitchNotificationsHiderTrackerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/DisplaySwitchNotificationsHiderTrackerTest.kt
index 1dfcb38..578950f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/DisplaySwitchNotificationsHiderTrackerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/DisplaySwitchNotificationsHiderTrackerTest.kt
@@ -15,6 +15,7 @@
*/
package com.android.systemui.statusbar.notification.stack
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.internal.util.LatencyTracker
import com.android.internal.util.LatencyTracker.ACTION_NOTIFICATIONS_HIDDEN_FOR_MEASURE
@@ -31,12 +32,14 @@
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
+import org.junit.runner.RunWith
import org.mockito.Mockito.clearInvocations
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
@SmallTest
@OptIn(ExperimentalCoroutinesApi::class)
+@RunWith(AndroidJUnit4::class)
class DisplaySwitchNotificationsHiderTrackerTest : SysuiTestCase() {
private val testScope = TestScope()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt
index a6fb718..d28e0c1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt
@@ -5,6 +5,7 @@
import android.platform.test.annotations.DisableFlags
import android.platform.test.annotations.EnableFlags
import android.widget.FrameLayout
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.keyguard.BouncerPanelExpansionCalculator.aboutToShowBouncerProgress
import com.android.systemui.SysuiTestCase
@@ -37,6 +38,7 @@
import org.junit.Before
import org.junit.Rule
import org.junit.Test
+import org.junit.runner.RunWith
import org.mockito.Mockito.any
import org.mockito.Mockito.eq
import org.mockito.Mockito.mock
@@ -44,6 +46,7 @@
import org.mockito.Mockito.`when` as whenever
@SmallTest
+@RunWith(AndroidJUnit4::class)
class StackScrollAlgorithmTest : SysuiTestCase() {
@JvmField @Rule var expect: Expect = Expect.create()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ManagedProfileControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ManagedProfileControllerImplTest.kt
index c44c178..2f81027 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ManagedProfileControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ManagedProfileControllerImplTest.kt
@@ -18,6 +18,7 @@
import android.content.pm.UserInfo
import android.os.UserManager
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.settings.UserTracker
@@ -29,12 +30,14 @@
import junit.framework.Assert
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.Mockito.`when`
import org.mockito.MockitoAnnotations
@SmallTest
+@RunWith(AndroidJUnit4::class)
class ManagedProfileControllerImplTest : SysuiTestCase() {
private val mainExecutor: FakeExecutor = FakeExecutor(FakeSystemClock())
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt
index ba38f87..25314f3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt
@@ -27,6 +27,7 @@
import android.view.ViewTreeObserver
import android.view.ViewTreeObserver.OnPreDrawListener
import android.widget.FrameLayout
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import androidx.test.platform.app.InstrumentationRegistry
import com.android.systemui.SysuiTestCase
@@ -54,6 +55,7 @@
import javax.inject.Provider
import org.junit.Before
import org.junit.Test
+import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
import org.mockito.Mock
import org.mockito.Mockito.mock
@@ -64,6 +66,7 @@
import org.mockito.MockitoAnnotations
@SmallTest
+@RunWith(AndroidJUnit4::class)
class PhoneStatusBarViewControllerTest : SysuiTestCase() {
@Mock private lateinit var shadeViewController: ShadeViewController
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/domain/interactor/LightsOutInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/domain/interactor/LightsOutInteractorTest.kt
index 5a0e13d..2d9880a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/domain/interactor/LightsOutInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/domain/interactor/LightsOutInteractorTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.phone.domain.interactor
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
@@ -25,8 +26,10 @@
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.test.runTest
import org.junit.Test
+import org.junit.runner.RunWith
@SmallTest
+@RunWith(AndroidJUnit4::class)
class LightsOutInteractorTest : SysuiTestCase() {
private val statusBarModeRepository = FakeStatusBarModeRepository()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentLoggerTest.kt
index e0f1e1a..219b16f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentLoggerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentLoggerTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.phone.fragment
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.dump.DumpManager
@@ -26,9 +27,11 @@
import java.io.PrintWriter
import java.io.StringWriter
import org.junit.Test
+import org.junit.runner.RunWith
import org.mockito.Mockito.mock
@SmallTest
+@RunWith(AndroidJUnit4::class)
class CollapsedStatusBarFragmentLoggerTest : SysuiTestCase() {
private val buffer = LogBufferFactory(DumpManager(), mock(LogcatEchoTracker::class.java))
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/StatusBarVisibilityModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/StatusBarVisibilityModelTest.kt
index 022b5d2..9f6f51a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/StatusBarVisibilityModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/StatusBarVisibilityModelTest.kt
@@ -19,14 +19,17 @@
import android.app.StatusBarManager.DISABLE_NOTIFICATION_ICONS
import android.app.StatusBarManager.DISABLE_ONGOING_CALL_CHIP
import android.app.StatusBarManager.DISABLE_SYSTEM_INFO
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.statusbar.phone.fragment.StatusBarVisibilityModel.Companion.createDefaultModel
import com.android.systemui.statusbar.phone.fragment.StatusBarVisibilityModel.Companion.createModelFromFlags
import com.google.common.truth.Truth.assertThat
import org.junit.Test
+import org.junit.runner.RunWith
@SmallTest
+@RunWith(AndroidJUnit4::class)
class StatusBarVisibilityModelTest : SysuiTestCase() {
@Test
fun createDefaultModel_everythingEnabled() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt
index 7273d9f..5174ec7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt
@@ -25,11 +25,11 @@
import android.platform.test.annotations.DisableFlags
import android.platform.test.annotations.EnableFlags
import android.service.notification.NotificationListenerService.REASON_USER_STOPPED
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.view.LayoutInflater
import android.view.View
import android.widget.LinearLayout
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.internal.logging.testing.UiEventLoggerFake
import com.android.systemui.Flags.FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS
@@ -80,7 +80,7 @@
private const val PROC_STATE_INVISIBLE = ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@TestableLooper.RunWithLooper
@OptIn(ExperimentalCoroutinesApi::class)
class OngoingCallControllerTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallLoggerTest.kt
index ecec124..5ce936d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallLoggerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallLoggerTest.kt
@@ -16,13 +16,16 @@
package com.android.systemui.statusbar.phone.ongoingcall
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.internal.logging.testing.UiEventLoggerFake
import com.android.systemui.SysuiTestCase
import com.google.common.truth.Truth.assertThat
import org.junit.Test
+import org.junit.runner.RunWith
@SmallTest
+@RunWith(AndroidJUnit4::class)
class OngoingCallLoggerTest : SysuiTestCase() {
private val uiEventLoggerFake = UiEventLoggerFake()
private val ongoingCallLogger = OngoingCallLogger(uiEventLoggerFake)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/data/repository/OngoingCallRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/data/repository/OngoingCallRepositoryTest.kt
index d6624ca..27c2366 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/data/repository/OngoingCallRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/data/repository/OngoingCallRepositoryTest.kt
@@ -16,13 +16,16 @@
package com.android.systemui.statusbar.phone.ongoingcall.data.repository
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.statusbar.phone.ongoingcall.shared.model.OngoingCallModel
import com.google.common.truth.Truth.assertThat
import org.junit.Test
+import org.junit.runner.RunWith
@SmallTest
+@RunWith(AndroidJUnit4::class)
class OngoingCallRepositoryTest : SysuiTestCase() {
private val underTest = OngoingCallRepository()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ui/StatusBarIconControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ui/StatusBarIconControllerImplTest.kt
index 7e523fb..19abbd5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ui/StatusBarIconControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ui/StatusBarIconControllerImplTest.kt
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.phone.ui
import android.os.UserHandle
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.internal.statusbar.StatusBarIcon
import com.android.systemui.SysuiTestCase
@@ -32,11 +33,13 @@
import com.google.common.truth.Truth.assertThat
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(AndroidJUnit4::class)
class StatusBarIconControllerImplTest : SysuiTestCase() {
private lateinit var underTest: StatusBarIconControllerImpl
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ui/StatusBarIconControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ui/StatusBarIconControllerTest.java
index 14bce9c..891ff38 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ui/StatusBarIconControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ui/StatusBarIconControllerTest.java
@@ -25,11 +25,11 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper.RunWithLooper;
import android.view.ViewGroup;
import android.widget.LinearLayout;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.internal.statusbar.StatusBarIcon;
@@ -55,7 +55,7 @@
import org.junit.Test;
import org.junit.runner.RunWith;
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@RunWithLooper(setAsMainLooper = true)
@SmallTest
public class StatusBarIconControllerTest extends LeakCheckedTest {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/airplane/ui/viewmodel/AirplaneModeViewModelImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/airplane/ui/viewmodel/AirplaneModeViewModelImplTest.kt
index 1c9f523..b823333 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/airplane/ui/viewmodel/AirplaneModeViewModelImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/airplane/ui/viewmodel/AirplaneModeViewModelImplTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.pipeline.airplane.ui.viewmodel
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.log.table.TableLogBuffer
@@ -33,12 +34,14 @@
import kotlinx.coroutines.runBlocking
import org.junit.Before
import org.junit.Test
+import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.MockitoAnnotations
@SmallTest
@OptIn(ExperimentalCoroutinesApi::class)
@Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
+@RunWith(AndroidJUnit4::class)
class AirplaneModeViewModelImplTest : SysuiTestCase() {
private lateinit var underTest: AirplaneModeViewModelImpl
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/ethernet/domain/EthernetInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/ethernet/domain/EthernetInteractorTest.kt
index 6028712..f9ae5ff 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/ethernet/domain/EthernetInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/ethernet/domain/EthernetInteractorTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.pipeline.ethernet.domain
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.settingslib.AccessibilityContentDescriptions
import com.android.systemui.res.R
@@ -28,8 +29,10 @@
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runTest
import org.junit.Test
+import org.junit.runner.RunWith
@SmallTest
+@RunWith(AndroidJUnit4::class)
class EthernetInteractorTest : SysuiTestCase() {
private val connectivityRepository = FakeConnectivityRepository()
private val underTest = EthernetInteractor(connectivityRepository)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/model/SystemUiCarrierConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/model/SystemUiCarrierConfigTest.kt
index 3de50c9..4a2f6f2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/model/SystemUiCarrierConfigTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/model/SystemUiCarrierConfigTest.kt
@@ -21,15 +21,18 @@
import android.telephony.CarrierConfigManager.KEY_INFLATE_SIGNAL_STRENGTH_BOOL
import android.telephony.CarrierConfigManager.KEY_SHOW_5G_SLICE_ICON_BOOL
import android.telephony.CarrierConfigManager.KEY_SHOW_OPERATOR_NAME_IN_STATUSBAR_BOOL
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import org.junit.Before
import org.junit.Test
+import org.junit.runner.RunWith
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
+@RunWith(AndroidJUnit4::class)
class SystemUiCarrierConfigTest : SysuiTestCase() {
lateinit var underTest: SystemUiCarrierConfig
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepositoryTest.kt
index 932c4a1..320c148 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepositoryTest.kt
@@ -20,6 +20,7 @@
import android.os.PersistableBundle
import android.telephony.CarrierConfigManager
import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession
import com.android.systemui.SysuiTestCase
@@ -37,6 +38,7 @@
import org.junit.After
import org.junit.Before
import org.junit.Test
+import org.junit.runner.RunWith
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.Mock
import org.mockito.MockitoAnnotations
@@ -45,6 +47,7 @@
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
+@RunWith(AndroidJUnit4::class)
class CarrierConfigRepositoryTest : SysuiTestCase() {
private val testDispatcher = UnconfinedTestDispatcher()
private val testScope = TestScope(testDispatcher)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionParameterizedTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionParameterizedTest.kt
index 6785de93..db6f5927 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionParameterizedTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionParameterizedTest.kt
@@ -43,11 +43,12 @@
import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.runTest
import org.junit.After
+import platform.test.runner.parameterized.ParameterizedAndroidJunit4
+import platform.test.runner.parameterized.Parameters
+import platform.test.runner.parameterized.Parameter
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-import org.junit.runners.Parameterized
-import org.junit.runners.Parameterized.Parameters
/**
* Parameterized test for all of the common values of [FakeNetworkEventModel]. This test simply
@@ -56,7 +57,7 @@
*/
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
-@RunWith(Parameterized::class)
+@RunWith(ParameterizedAndroidJunit4::class)
internal class DemoMobileConnectionParameterizedTest(private val testCase: TestCase) :
SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepositoryTest.kt
index a41bc0d..5e0d2fb0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepositoryTest.kt
@@ -19,6 +19,7 @@
import android.telephony.TelephonyManager.DATA_ACTIVITY_INOUT
import android.telephony.TelephonyManager.DATA_ACTIVITY_NONE
import android.telephony.TelephonyManager.UNKNOWN_CARRIER_ID
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.settingslib.SignalIcon
import com.android.settingslib.mobile.TelephonyIcons.THREE_G
@@ -49,9 +50,11 @@
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
+import org.junit.runner.RunWith
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
+@RunWith(AndroidJUnit4::class)
class DemoMobileConnectionsRepositoryTest : SysuiTestCase() {
private val dumpManager: DumpManager = mock()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryTest.kt
index 3c13906..fd4c370 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryTest.kt
@@ -23,6 +23,7 @@
import android.telephony.SubscriptionManager.PROFILE_CLASS_UNSET
import android.telephony.TelephonyCallback
import android.telephony.TelephonyManager
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
@@ -58,6 +59,7 @@
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
+import org.junit.runner.RunWith
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
@@ -69,6 +71,7 @@
@Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
+@RunWith(AndroidJUnit4::class)
class FullMobileConnectionRepositoryTest : SysuiTestCase() {
private lateinit var underTest: FullMobileConnectionRepository
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt
index 6d8bf55..8fd0b31 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt
@@ -66,6 +66,7 @@
import android.telephony.TelephonyManager.EXTRA_SUBSCRIPTION_ID
import android.telephony.TelephonyManager.NETWORK_TYPE_LTE
import android.telephony.TelephonyManager.NETWORK_TYPE_UNKNOWN
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.settingslib.mobile.MobileMappings
import com.android.systemui.SysuiTestCase
@@ -107,6 +108,7 @@
import kotlinx.coroutines.test.runTest
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
@@ -114,6 +116,7 @@
@Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
+@RunWith(AndroidJUnit4::class)
class MobileConnectionRepositoryTest : SysuiTestCase() {
private lateinit var underTest: MobileConnectionRepositoryImpl
private lateinit var connectionsRepo: FakeMobileConnectionsRepository
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt
index 1488418..30e96f1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt
@@ -20,6 +20,7 @@
import android.telephony.CellSignalStrength
import android.telephony.SubscriptionManager.PROFILE_CLASS_UNSET
import android.telephony.TelephonyManager.NETWORK_TYPE_UNKNOWN
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.settingslib.mobile.MobileIconCarrierIdOverrides
import com.android.settingslib.mobile.MobileIconCarrierIdOverridesImpl
@@ -52,11 +53,13 @@
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
+import org.junit.runner.RunWith
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.ArgumentMatchers.anyString
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
+@RunWith(AndroidJUnit4::class)
class MobileIconInteractorTest : SysuiTestCase() {
private lateinit var underTest: MobileIconInteractor
private val mobileMappingsProxy = FakeMobileMappingsProxy()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt
index 58d9ee3..cc0eae7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt
@@ -21,6 +21,7 @@
import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
import android.telephony.SubscriptionManager.PROFILE_CLASS_PROVISIONING
import android.telephony.SubscriptionManager.PROFILE_CLASS_UNSET
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.settingslib.mobile.MobileMappings
import com.android.systemui.SysuiTestCase
@@ -50,11 +51,13 @@
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
+import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.MockitoAnnotations
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
+@RunWith(AndroidJUnit4::class)
class MobileIconsInteractorTest : SysuiTestCase() {
private lateinit var underTest: MobileIconsInteractor
private lateinit var connectivityRepository: FakeConnectivityRepository
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileViewLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileViewLoggerTest.kt
index 755aaa6..4511be9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileViewLoggerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileViewLoggerTest.kt
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.pipeline.mobile.ui
import android.widget.TextView
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.dump.DumpManager
@@ -32,10 +33,12 @@
import java.io.StringWriter
import org.junit.Before
import org.junit.Test
+import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.MockitoAnnotations
@SmallTest
+@RunWith(AndroidJUnit4::class)
class MobileViewLoggerTest : SysuiTestCase() {
private val buffer = LogBufferFactory(DumpManager(), mock()).create("buffer", 10)
private val stringWriter = StringWriter()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/data/DeviceBasedSatelliteRepositorySwitcherTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/data/DeviceBasedSatelliteRepositorySwitcherTest.kt
index cdc4733..fc1ea22 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/data/DeviceBasedSatelliteRepositorySwitcherTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/data/DeviceBasedSatelliteRepositorySwitcherTest.kt
@@ -18,6 +18,7 @@
import android.telephony.TelephonyManager
import android.telephony.satellite.SatelliteManager
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
@@ -41,9 +42,11 @@
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Test
+import org.junit.runner.RunWith
import org.mockito.Mockito.verify
@SmallTest
+@RunWith(AndroidJUnit4::class)
class DeviceBasedSatelliteRepositorySwitcherTest : SysuiTestCase() {
private val testDispatcher = StandardTestDispatcher()
private val testScope = TestScope(testDispatcher)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/data/demo/DemoDeviceBasedSatelliteRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/data/demo/DemoDeviceBasedSatelliteRepositoryTest.kt
index f77fd19..8769389 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/data/demo/DemoDeviceBasedSatelliteRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/data/demo/DemoDeviceBasedSatelliteRepositoryTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.pipeline.satellite.data.demo
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
@@ -29,8 +30,10 @@
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runTest
import org.junit.Before
+import org.junit.runner.RunWith
@SmallTest
+@RunWith(AndroidJUnit4::class)
class DemoDeviceBasedSatelliteRepositoryTest : SysuiTestCase() {
private val testDispatcher = StandardTestDispatcher()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/DeviceBasedSatelliteRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/DeviceBasedSatelliteRepositoryImplTest.kt
index 890a2e4..73ac6e3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/DeviceBasedSatelliteRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/DeviceBasedSatelliteRepositoryImplTest.kt
@@ -32,10 +32,12 @@
import android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_OFF
import android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_UNAVAILABLE
import android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_UNKNOWN
+import android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_ERROR
import android.telephony.satellite.SatelliteManager.SatelliteException
import android.telephony.satellite.SatelliteModemStateCallback
import android.telephony.satellite.SatelliteProvisionStateCallback
import android.telephony.satellite.SatelliteSupportedStateCallback
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
@@ -60,8 +62,10 @@
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
+import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.Mockito
+import org.mockito.Mockito.atLeastOnce
import org.mockito.Mockito.doAnswer
import org.mockito.Mockito.never
import org.mockito.Mockito.times
@@ -71,6 +75,7 @@
@Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
+@RunWith(AndroidJUnit4::class)
class DeviceBasedSatelliteRepositoryImplTest : SysuiTestCase() {
private lateinit var underTest: DeviceBasedSatelliteRepositoryImpl
@@ -354,13 +359,142 @@
}
@Test
- fun satelliteProvisioned_supported_tracksCallback() =
+ fun satelliteProvisioned_returnsException_defaultsToFalse() =
+ testScope.runTest {
+ // GIVEN satellite is supported on device
+ doAnswer {
+ val callback: OutcomeReceiver<Boolean, SatelliteException> =
+ it.getArgument(1) as OutcomeReceiver<Boolean, SatelliteException>
+ callback.onResult(true)
+ }
+ .whenever(satelliteManager)
+ .requestIsSupported(any(), any())
+
+ // GIVEN satellite returns an error when asked if provisioned
+ doAnswer {
+ val receiver = it.arguments[1] as OutcomeReceiver<Boolean, SatelliteException>
+ receiver.onError(SatelliteException(SATELLITE_RESULT_ERROR))
+ null
+ }
+ .whenever(satelliteManager)
+ .requestIsProvisioned(
+ any(),
+ any<OutcomeReceiver<Boolean, SatelliteException>>()
+ )
+
+ // GIVEN we've been up long enough to start querying
+ systemClock.setUptimeMillis(Process.getStartUptimeMillis() + MIN_UPTIME)
+
+ underTest =
+ DeviceBasedSatelliteRepositoryImpl(
+ Optional.of(satelliteManager),
+ telephonyManager,
+ dispatcher,
+ testScope.backgroundScope,
+ logBuffer = FakeLogBuffer.Factory.create(),
+ verboseLogBuffer = FakeLogBuffer.Factory.create(),
+ systemClock,
+ )
+
+ // WHEN we try to check for provisioned status
+ val provisioned by collectLastValue(underTest.isSatelliteProvisioned)
+
+ // THEN well, first we don't throw...
+ // AND THEN we assume that it's not provisioned
+ assertThat(provisioned).isFalse()
+ }
+
+ @Test
+ fun satelliteProvisioned_throwsWhenQuerying_defaultsToFalse() =
+ testScope.runTest {
+ // GIVEN satellite is supported on device
+ doAnswer {
+ val callback: OutcomeReceiver<Boolean, SatelliteException> =
+ it.getArgument(1) as OutcomeReceiver<Boolean, SatelliteException>
+ callback.onResult(true)
+ }
+ .whenever(satelliteManager)
+ .requestIsSupported(any(), any())
+
+ // GIVEN satellite throws when asked if provisioned
+ whenever(satelliteManager.requestIsProvisioned(any(), any()))
+ .thenThrow(SecurityException())
+
+ // GIVEN we've been up long enough to start querying
+ systemClock.setUptimeMillis(Process.getStartUptimeMillis() + MIN_UPTIME)
+
+ underTest =
+ DeviceBasedSatelliteRepositoryImpl(
+ Optional.of(satelliteManager),
+ telephonyManager,
+ dispatcher,
+ testScope.backgroundScope,
+ logBuffer = FakeLogBuffer.Factory.create(),
+ verboseLogBuffer = FakeLogBuffer.Factory.create(),
+ systemClock,
+ )
+
+ // WHEN we try to check for provisioned status
+ val provisioned by collectLastValue(underTest.isSatelliteProvisioned)
+
+ // THEN well, first we don't throw...
+ // AND THEN we assume that it's not provisioned
+ assertThat(provisioned).isFalse()
+ }
+
+ @Test
+ fun satelliteProvisioned_supported_provisioned_queriesInitialStateBeforeCallbacks() =
+ testScope.runTest {
+ // GIVEN satellite is supported, and provisioned
+ setUpRepo(
+ uptime = MIN_UPTIME,
+ satMan = satelliteManager,
+ satelliteSupported = true,
+ initialSatelliteIsProvisioned = true,
+ )
+
+ val provisioned by collectLastValue(underTest.isSatelliteProvisioned)
+
+ runCurrent()
+
+ // THEN the current state is requested
+ verify(satelliteManager, atLeastOnce()).requestIsProvisioned(any(), any())
+
+ // AND the state is correct
+ assertThat(provisioned).isTrue()
+ }
+
+ @Test
+ fun satelliteProvisioned_supported_notProvisioned_queriesInitialStateBeforeCallbacks() =
+ testScope.runTest {
+ // GIVEN satellite is supported, and provisioned
+ setUpRepo(
+ uptime = MIN_UPTIME,
+ satMan = satelliteManager,
+ satelliteSupported = true,
+ initialSatelliteIsProvisioned = false,
+ )
+
+ val provisioned by collectLastValue(underTest.isSatelliteProvisioned)
+
+ runCurrent()
+
+ // THEN the current state is requested
+ verify(satelliteManager, atLeastOnce()).requestIsProvisioned(any(), any())
+
+ // AND the state is correct
+ assertThat(provisioned).isFalse()
+ }
+
+ @Test
+ fun satelliteProvisioned_supported_notInitiallyProvisioned_tracksCallback() =
testScope.runTest {
// GIVEN satellite is not supported
setUpRepo(
uptime = MIN_UPTIME,
satMan = satelliteManager,
satelliteSupported = true,
+ initialSatelliteIsProvisioned = false,
)
val provisioned by collectLastValue(underTest.isSatelliteProvisioned)
@@ -416,6 +550,8 @@
// THEN listeners are re-registered
verify(satelliteManager, times(2)).registerForProvisionStateChanged(any(), any())
+ // AND the state is queried again
+ verify(satelliteManager, times(2)).requestIsProvisioned(any(), any())
}
@Test
@@ -632,6 +768,7 @@
uptime: Long = MIN_UPTIME,
satMan: SatelliteManager? = satelliteManager,
satelliteSupported: Boolean = true,
+ initialSatelliteIsProvisioned: Boolean = true,
) {
doAnswer {
val callback: OutcomeReceiver<Boolean, SatelliteException> =
@@ -641,6 +778,14 @@
.whenever(satelliteManager)
.requestIsSupported(any(), any())
+ doAnswer {
+ val callback: OutcomeReceiver<Boolean, SatelliteException> =
+ it.getArgument(1) as OutcomeReceiver<Boolean, SatelliteException>
+ callback.onResult(initialSatelliteIsProvisioned)
+ }
+ .whenever(satelliteManager)
+ .requestIsProvisioned(any(), any())
+
systemClock.setUptimeMillis(Process.getStartUptimeMillis() + uptime)
underTest =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractorTest.kt
index 2e5ebb3..cd0390e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractorTest.kt
@@ -18,6 +18,7 @@
import android.platform.test.annotations.DisableFlags
import android.platform.test.annotations.EnableFlags
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.internal.telephony.flags.Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG
import com.android.systemui.SysuiTestCase
@@ -38,8 +39,10 @@
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runTest
import org.junit.Before
+import org.junit.runner.RunWith
@SmallTest
+@RunWith(AndroidJUnit4::class)
class DeviceBasedSatelliteInteractorTest : SysuiTestCase() {
private lateinit var underTest: DeviceBasedSatelliteInteractor
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/ui/viewmodel/DeviceBasedSatelliteViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/ui/viewmodel/DeviceBasedSatelliteViewModelTest.kt
index c39e301..64b07fc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/ui/viewmodel/DeviceBasedSatelliteViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/ui/viewmodel/DeviceBasedSatelliteViewModelTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.pipeline.satellite.ui.viewmodel
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.common.shared.model.Icon
@@ -41,9 +42,11 @@
import kotlinx.coroutines.test.advanceTimeBy
import kotlinx.coroutines.test.runTest
import org.junit.Before
+import org.junit.runner.RunWith
import org.mockito.MockitoAnnotations
@SmallTest
+@RunWith(AndroidJUnit4::class)
class DeviceBasedSatelliteViewModelTest : SysuiTestCase() {
private lateinit var underTest: DeviceBasedSatelliteViewModel
private lateinit var interactor: DeviceBasedSatelliteInteractor
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/data/model/DefaultConnectionModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/data/model/DefaultConnectionModelTest.kt
index c43778a..4c2bb7f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/data/model/DefaultConnectionModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/data/model/DefaultConnectionModelTest.kt
@@ -16,13 +16,16 @@
package com.android.systemui.statusbar.pipeline.shared.data.model
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.log.LogMessageImpl
import com.google.common.truth.Truth.assertThat
import org.junit.Test
+import org.junit.runner.RunWith
@SmallTest
+@RunWith(AndroidJUnit4::class)
class DefaultConnectionModelTest : SysuiTestCase() {
@Test
fun messageInitializerAndPrinter_isValidatedFalse_hasCorrectInfo() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/data/repository/ConnectivityRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/data/repository/ConnectivityRepositoryImplTest.kt
index fa4e91b..f486787 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/data/repository/ConnectivityRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/data/repository/ConnectivityRepositoryImplTest.kt
@@ -25,6 +25,7 @@
import android.net.vcn.VcnTransportInfo
import android.net.wifi.WifiInfo
import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.dump.DumpManager
@@ -50,6 +51,7 @@
import kotlinx.coroutines.yield
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.Mockito.`when` as whenever
@@ -57,6 +59,7 @@
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
+@RunWith(AndroidJUnit4::class)
class ConnectivityRepositoryImplTest : SysuiTestCase() {
private lateinit var underTest: ConnectivityRepositoryImpl
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/view/ModernStatusBarViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/view/ModernStatusBarViewTest.kt
index 028a58c..c3ad0f9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/view/ModernStatusBarViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/view/ModernStatusBarViewTest.kt
@@ -17,8 +17,8 @@
package com.android.systemui.statusbar.pipeline.shared.ui.view
import android.graphics.Rect
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.statusbar.StatusBarIconView.STATE_DOT
@@ -30,7 +30,7 @@
import org.junit.runner.RunWith
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@RunWithLooper(setAsMainLooper = true)
class ModernStatusBarViewTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/view/SingleBindableStatusBarIconViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/view/SingleBindableStatusBarIconViewTest.kt
index ca9df57..a6cdfe2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/view/SingleBindableStatusBarIconViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/view/SingleBindableStatusBarIconViewTest.kt
@@ -17,8 +17,8 @@
package com.android.systemui.statusbar.pipeline.shared.ui.view
import android.graphics.Rect
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.statusbar.StatusBarIconView
@@ -32,7 +32,7 @@
* method.
*/
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
class SingleBindableStatusBarIconViewTest : SysuiTestCase() {
private lateinit var binding: SingleBindableStatusBarIconViewBinding
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModelImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModelImplTest.kt
index 92de866..b4c6106 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModelImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModelImplTest.kt
@@ -18,6 +18,7 @@
import android.platform.test.annotations.DisableFlags
import android.platform.test.annotations.EnableFlags
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
@@ -60,9 +61,11 @@
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
+import org.junit.runner.RunWith
@SmallTest
@OptIn(ExperimentalCoroutinesApi::class)
+@RunWith(AndroidJUnit4::class)
class CollapsedStatusBarViewModelImplTest : SysuiTestCase() {
private val kosmos =
Kosmos().also {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/InternetTileViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/InternetTileViewModelTest.kt
index 0cb3329..2238bff 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/InternetTileViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/InternetTileViewModelTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.pipeline.shared.ui.viewmodel
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.settingslib.AccessibilityContentDescriptions.WIFI_OTHER_DEVICE_CONNECTION
import com.android.systemui.SysuiTestCase
@@ -55,8 +56,10 @@
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
+import org.junit.runner.RunWith
@SmallTest
+@RunWith(AndroidJUnit4::class)
class InternetTileViewModelTest : SysuiTestCase() {
private lateinit var underTest: InternetTileViewModel
private lateinit var mobileIconsInteractor: MobileIconsInteractor
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/shared/model/WifiNetworkModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/shared/model/WifiNetworkModelTest.kt
index ba035be..eb6b068 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/shared/model/WifiNetworkModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/shared/model/WifiNetworkModelTest.kt
@@ -18,6 +18,7 @@
import android.net.wifi.WifiManager.UNKNOWN_SSID
import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.log.table.TableRowLogger
@@ -25,8 +26,10 @@
import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel.Companion.MIN_VALID_LEVEL
import com.google.common.truth.Truth.assertThat
import org.junit.Test
+import org.junit.runner.RunWith
@SmallTest
+@RunWith(AndroidJUnit4::class)
class WifiNetworkModelTest : SysuiTestCase() {
@Test
fun active_levelsInValidRange_noException() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BluetoothControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BluetoothControllerImplTest.java
index 9ab64d65..93071bd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BluetoothControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BluetoothControllerImplTest.java
@@ -43,6 +43,7 @@
import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.settingslib.bluetooth.BluetoothEventManager;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CastControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CastControllerImplTest.java
index 6894e6c..59b20c8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CastControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CastControllerImplTest.java
@@ -13,9 +13,9 @@
import android.media.MediaRouter;
import android.media.projection.MediaProjectionInfo;
import android.media.projection.MediaProjectionManager;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -34,7 +34,7 @@
import java.util.concurrent.atomic.AtomicBoolean;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper
public class CastControllerImplTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ClockTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ClockTest.kt
index 22c72cc..7549a7f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ClockTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ClockTest.kt
@@ -16,12 +16,12 @@
package com.android.systemui.statusbar.policy
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.view.View.MeasureSpec.UNSPECIFIED
import android.view.View.MeasureSpec.makeMeasureSpec
import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
import android.widget.LinearLayout
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import org.junit.Before
@@ -31,7 +31,7 @@
import org.junit.Test
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@TestableLooper.RunWithLooper
class ClockTest : SysuiTestCase() {
private lateinit var clockView: Clock
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DevicePostureControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DevicePostureControllerImplTest.kt
index c606511..f871d27 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DevicePostureControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DevicePostureControllerImplTest.kt
@@ -18,9 +18,9 @@
import android.hardware.devicestate.DeviceState
import android.hardware.devicestate.DeviceStateManager
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.testing.TestableResources
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_CLOSED
@@ -44,7 +44,7 @@
import org.mockito.MockitoAnnotations
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
class DevicePostureControllerImplTest : SysuiTestCase() {
private val useBaseStateDeviceState = SUPPORTED_POSTURES_SIZE
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImplTest.kt
index 31bd57e..649a4ab 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImplTest.kt
@@ -18,8 +18,8 @@
import android.os.Handler
import android.provider.Settings
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.dump.DumpManager
@@ -45,7 +45,7 @@
import org.mockito.MockitoAnnotations
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@TestableLooper.RunWithLooper
class DeviceProvisionedControllerImplTest : SysuiTestCase() {
@@ -246,4 +246,4 @@
`when`(userTracker.userId).thenReturn(toUser)
userTrackerCallbackCaptor.value.onUserChanged(toUser, mContext)
}
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ExtensionControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ExtensionControllerImplTest.java
index 683136d..f5efd6d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ExtensionControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ExtensionControllerImplTest.java
@@ -23,10 +23,10 @@
import static org.mockito.Mockito.when;
import android.content.res.Configuration;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -51,7 +51,7 @@
import java.util.Map;
import java.util.function.Consumer;
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@SmallTest
public class ExtensionControllerImplTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HotspotControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HotspotControllerImplTest.java
index 784fb71..3721b0e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HotspotControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HotspotControllerImplTest.java
@@ -33,9 +33,9 @@
import android.net.wifi.WifiManager;
import android.os.Handler;
import android.os.UserManager;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -57,7 +57,7 @@
import java.util.concurrent.Executor;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper
public class HotspotControllerImplTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchControllerTest.kt
index 1250228..b7a3515 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchControllerTest.kt
@@ -16,12 +16,12 @@
package com.android.systemui.statusbar.policy
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.testing.ViewUtils
import android.view.LayoutInflater
import android.view.View
import android.widget.FrameLayout
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.internal.logging.UiEventLogger
import com.android.systemui.res.R
@@ -45,7 +45,7 @@
@SmallTest
@TestableLooper.RunWithLooper
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class KeyguardQsUserSwitchControllerTest : SysuiTestCase() {
@Mock
private lateinit var userSwitcherController: UserSwitcherController
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardStateControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardStateControllerTest.java
index 3a086ae..aed9af6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardStateControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardStateControllerTest.java
@@ -25,9 +25,9 @@
import static org.mockito.Mockito.when;
import android.hardware.biometrics.BiometricSourceType;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.internal.widget.LockPatternUtils;
@@ -54,7 +54,7 @@
@SmallTest
@TestableLooper.RunWithLooper
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
public class KeyguardStateControllerTest extends SysuiTestCase {
@Mock
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputQuickSettingsDisablerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputQuickSettingsDisablerTest.kt
index 635d63e..750f0c6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputQuickSettingsDisablerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputQuickSettingsDisablerTest.kt
@@ -15,8 +15,8 @@
import android.app.StatusBarManager
import android.content.res.Configuration
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.res.R
@@ -35,7 +35,7 @@
import org.mockito.MockitoAnnotations
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@RunWithLooper
class RemoteInputQuickSettingsDisablerTest : SysuiTestCase() {
@@ -134,4 +134,4 @@
private fun shouldDisableQs(state: Int): Boolean {
return state and StatusBarManager.DISABLE2_QUICK_SETTINGS != 0
}
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyConstantsTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyConstantsTest.java
index a9681e0..36e3052 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyConstantsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyConstantsTest.java
@@ -22,10 +22,10 @@
import android.app.RemoteInput;
import android.provider.DeviceConfig;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.testing.TestableResources;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
@@ -39,7 +39,7 @@
import org.junit.Test;
import org.junit.runner.RunWith;
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper
@SmallTest
public class SmartReplyConstantsTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ZenModeControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ZenModeControllerImplTest.java
index ddd29c3..637a0f1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ZenModeControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ZenModeControllerImplTest.java
@@ -27,10 +27,10 @@
import android.os.Handler;
import android.provider.Settings;
import android.service.notification.ZenModeConfig;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -51,7 +51,7 @@
import java.util.concurrent.atomic.AtomicInteger;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@RunWithLooper
public class ZenModeControllerImplTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/bluetooth/BluetoothRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/bluetooth/BluetoothRepositoryImplTest.kt
index 6f40f15..94f0d19 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/bluetooth/BluetoothRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/bluetooth/BluetoothRepositoryImplTest.kt
@@ -15,6 +15,7 @@
package com.android.systemui.statusbar.policy.bluetooth
import android.bluetooth.BluetoothProfile
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.settingslib.bluetooth.CachedBluetoothDevice
import com.android.settingslib.bluetooth.LocalBluetoothAdapter
@@ -30,11 +31,13 @@
import kotlinx.coroutines.test.TestScope
import org.junit.Before
import org.junit.Test
+import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.MockitoAnnotations
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
+@RunWith(AndroidJUnit4::class)
class BluetoothRepositoryImplTest : SysuiTestCase() {
private lateinit var underTest: BluetoothRepositoryImpl
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/domain/interactor/ZenModeInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/domain/interactor/ZenModeInteractorTest.kt
index dbb1062..8981009 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/domain/interactor/ZenModeInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/domain/interactor/ZenModeInteractorTest.kt
@@ -18,6 +18,7 @@
import android.app.NotificationManager.Policy
import android.provider.Settings
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysUITestComponent
import com.android.systemui.SysUITestModule
@@ -32,8 +33,10 @@
import dagger.BindsInstance
import dagger.Component
import org.junit.Test
+import org.junit.runner.RunWith
@SmallTest
+@RunWith(AndroidJUnit4::class)
class ZenModeInteractorTest : SysuiTestCase() {
@SysUISingleton
@Component(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/window/StatusBarWindowStateControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/window/StatusBarWindowStateControllerTest.kt
index 8576d4f..03a25e3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/window/StatusBarWindowStateControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/window/StatusBarWindowStateControllerTest.kt
@@ -21,18 +21,21 @@
import android.app.StatusBarManager.WINDOW_STATE_HIDDEN
import android.app.StatusBarManager.WINDOW_STATE_SHOWING
import android.app.StatusBarManager.WINDOW_STATUS_BAR
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.statusbar.CommandQueue
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
+import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
import org.mockito.Mock
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
@SmallTest
+@RunWith(AndroidJUnit4::class)
class StatusBarWindowStateControllerTest : SysuiTestCase() {
private lateinit var controller: StatusBarWindowStateController
private lateinit var callback: CommandQueue.Callbacks
diff --git a/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/glowboxeffect/GlowBoxEffectTest.kt b/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/glowboxeffect/GlowBoxEffectTest.kt
index 16132ba..32ef501 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/glowboxeffect/GlowBoxEffectTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/glowboxeffect/GlowBoxEffectTest.kt
@@ -18,8 +18,8 @@
import android.graphics.Color
import android.graphics.Paint
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.animation.AnimatorTestRule
@@ -31,7 +31,7 @@
import org.junit.runner.RunWith
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
class GlowBoxEffectTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/loadingeffect/LoadingEffectTest.kt b/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/loadingeffect/LoadingEffectTest.kt
index 41d7fd5..67a4219 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/loadingeffect/LoadingEffectTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/loadingeffect/LoadingEffectTest.kt
@@ -18,8 +18,8 @@
import android.graphics.Paint
import android.graphics.RenderEffect
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.animation.AnimatorTestRule
@@ -33,7 +33,7 @@
import org.junit.runner.RunWith
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
class LoadingEffectTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/ripple/MultiRippleControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/ripple/MultiRippleControllerTest.kt
index 0d19ab1..a5afe1e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/ripple/MultiRippleControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/ripple/MultiRippleControllerTest.kt
@@ -17,7 +17,7 @@
package com.android.systemui.surfaceeffects.ripple
import android.graphics.Color
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.surfaceeffects.ripple.MultiRippleController.Companion.MAX_RIPPLE_NUMBER
@@ -29,7 +29,7 @@
import org.junit.runner.RunWith
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class MultiRippleControllerTest : SysuiTestCase() {
private lateinit var multiRippleController: MultiRippleController
private lateinit var multiRippleView: MultiRippleView
diff --git a/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/ripple/RippleAnimationTest.kt b/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/ripple/RippleAnimationTest.kt
index 74ed7fb..8dafa82 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/ripple/RippleAnimationTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/ripple/RippleAnimationTest.kt
@@ -17,8 +17,8 @@
package com.android.systemui.surfaceeffects.ripple
import android.graphics.Color
-import android.testing.AndroidTestingRunner
import androidx.core.graphics.ColorUtils
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.util.concurrency.FakeExecutor
@@ -28,7 +28,7 @@
import org.junit.runner.RunWith
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class RippleAnimationTest : SysuiTestCase() {
private val fakeSystemClock = FakeSystemClock()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/ripple/RippleShaderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/ripple/RippleShaderTest.kt
index 89cc18cc..2fee2a4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/ripple/RippleShaderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/ripple/RippleShaderTest.kt
@@ -15,7 +15,7 @@
*/
package com.android.systemui.surfaceeffects.ripple
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.google.common.truth.Truth.assertThat
@@ -24,7 +24,7 @@
import org.junit.runner.RunWith
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class RippleShaderTest : SysuiTestCase() {
private lateinit var rippleShader: RippleShader
diff --git a/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/ripple/RippleViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/ripple/RippleViewTest.kt
index 1e5ab7e..18644ab 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/ripple/RippleViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/ripple/RippleViewTest.kt
@@ -15,7 +15,7 @@
*/
package com.android.systemui.surfaceeffects.ripple
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import org.junit.Before
@@ -23,7 +23,7 @@
import org.junit.runner.RunWith
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class RippleViewTest : SysuiTestCase() {
private lateinit var rippleView: RippleView
diff --git a/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/shaders/SolidColorShaderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/shaders/SolidColorShaderTest.kt
index f1fadf6..fbd3eae 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/shaders/SolidColorShaderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/shaders/SolidColorShaderTest.kt
@@ -16,14 +16,14 @@
package com.android.systemui.surfaceeffects.shaders
import android.graphics.Color
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import org.junit.Test
import org.junit.runner.RunWith
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class SolidColorShaderTest : SysuiTestCase() {
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/shaders/SparkleShaderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/shaders/SparkleShaderTest.kt
index 64ea6a6..d32bffb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/shaders/SparkleShaderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/shaders/SparkleShaderTest.kt
@@ -16,14 +16,14 @@
package com.android.systemui.surfaceeffects.shaders
import android.graphics.Color
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import org.junit.Test
import org.junit.runner.RunWith
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class SparkleShaderTest : SysuiTestCase() {
private lateinit var sparkleShader: SparkleShader
diff --git a/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseControllerTest.kt
index 08b49f0..4ba6438 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseControllerTest.kt
@@ -16,9 +16,9 @@
package com.android.systemui.surfaceeffects.turbulencenoise
import android.graphics.Color
-import android.testing.AndroidTestingRunner
import android.view.View.INVISIBLE
import android.view.View.VISIBLE
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.surfaceeffects.turbulencenoise.TurbulenceNoiseController.Companion.AnimationState.EASE_IN
@@ -33,7 +33,7 @@
import org.junit.runner.RunWith
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class TurbulenceNoiseControllerTest : SysuiTestCase() {
private val fakeSystemClock = FakeSystemClock()
// FakeExecutor is needed to run animator.
diff --git a/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseShaderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseShaderTest.kt
index e62ca64..286f017 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseShaderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseShaderTest.kt
@@ -15,7 +15,7 @@
*/
package com.android.systemui.surfaceeffects.turbulencenoise
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.surfaceeffects.turbulencenoise.TurbulenceNoiseShader.Companion.Type.SIMPLEX_NOISE
@@ -25,7 +25,7 @@
import org.junit.runner.RunWith
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class TurbulenceNoiseShaderTest : SysuiTestCase() {
private lateinit var turbulenceNoiseShader: TurbulenceNoiseShader
diff --git a/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseViewTest.kt
index 953071c..e09d4ea 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseViewTest.kt
@@ -16,7 +16,7 @@
package com.android.systemui.surfaceeffects.turbulencenoise
import android.graphics.Color
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.surfaceeffects.turbulencenoise.TurbulenceNoiseShader.Companion.Type.SIMPLEX_NOISE
@@ -28,7 +28,7 @@
import org.junit.runner.RunWith
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class TurbulenceNoiseViewTest : SysuiTestCase() {
private val fakeSystemClock = FakeSystemClock()
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 ae4dfbd..bb6ba46 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayControllerTest.kt
@@ -23,6 +23,7 @@
import android.view.ViewGroup
import android.view.WindowManager
import android.view.accessibility.AccessibilityManager
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.internal.logging.InstanceId
import com.android.internal.logging.testing.UiEventLoggerFake
@@ -44,6 +45,7 @@
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
+import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.Mockito.never
import org.mockito.Mockito.reset
@@ -53,6 +55,7 @@
import org.mockito.MockitoAnnotations
@SmallTest
+@RunWith(AndroidJUnit4::class)
class TemporaryViewDisplayControllerTest : SysuiTestCase() {
private lateinit var underTest: TestController
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 38c1a78..1dfd934 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewLoggerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewLoggerTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.temporarydisplay
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.internal.logging.InstanceId
import com.android.systemui.SysuiTestCase
@@ -28,9 +29,11 @@
import java.io.StringWriter
import org.junit.Before
import org.junit.Test
+import org.junit.runner.RunWith
import org.mockito.Mockito
@SmallTest
+@RunWith(AndroidJUnit4::class)
class TemporaryViewLoggerTest : SysuiTestCase() {
private lateinit var buffer: LogBuffer
private lateinit var logger: TemporaryViewLogger<TemporaryViewInfo>
diff --git a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewUiEventLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewUiEventLoggerTest.kt
index f707a8da..281ecfb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewUiEventLoggerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewUiEventLoggerTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.temporarydisplay
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.internal.logging.InstanceId
import com.android.internal.logging.testing.UiEventLoggerFake
@@ -23,8 +24,10 @@
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
+import org.junit.runner.RunWith
@SmallTest
+@RunWith(AndroidJUnit4::class)
class TemporaryViewUiEventLoggerTest : SysuiTestCase() {
private lateinit var uiEventLoggerFake: UiEventLoggerFake
private lateinit var logger: TemporaryViewUiEventLogger
diff --git a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TouchableRegionViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TouchableRegionViewControllerTest.kt
index 7586fe4..a230f06 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TouchableRegionViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TouchableRegionViewControllerTest.kt
@@ -19,12 +19,14 @@
import android.graphics.Rect
import android.view.View
import android.view.ViewTreeObserver
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.util.mockito.any
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
+import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
import org.mockito.Mock
import org.mockito.Mockito.verify
@@ -32,6 +34,7 @@
import org.mockito.MockitoAnnotations
@SmallTest
+@RunWith(AndroidJUnit4::class)
class TouchableRegionViewControllerTest : SysuiTestCase() {
@Mock private lateinit var view: View
diff --git a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/chipbar/SwipeChipbarAwayGestureHandlerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/chipbar/SwipeChipbarAwayGestureHandlerTest.kt
index c539246..75d031d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/chipbar/SwipeChipbarAwayGestureHandlerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/chipbar/SwipeChipbarAwayGestureHandlerTest.kt
@@ -19,6 +19,7 @@
import android.graphics.Rect
import android.view.MotionEvent
import android.view.View
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer
import com.android.systemui.SysuiTestCase
@@ -29,8 +30,10 @@
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
+import org.junit.runner.RunWith
@SmallTest
+@RunWith(AndroidJUnit4::class)
class SwipeChipbarAwayGestureHandlerTest : SysuiTestCase() {
private lateinit var underTest: SwipeChipbarAwayGestureHandler
diff --git a/packages/SystemUI/tests/src/com/android/systemui/touchpad/tutorial/ui/TouchpadTutorialViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/touchpad/tutorial/ui/TouchpadTutorialViewModelTest.kt
new file mode 100644
index 0000000..2300a1f
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/touchpad/tutorial/ui/TouchpadTutorialViewModelTest.kt
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.touchpad.tutorial.ui
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.model.sysUiState
+import com.android.systemui.settings.displayTracker
+import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_TOUCHPAD_GESTURES_DISABLED
+import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags
+import com.android.systemui.testKosmos
+import com.android.systemui.touchpad.tutorial.domain.interactor.TouchpadGesturesInteractor
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class TouchpadTutorialViewModelTest : SysuiTestCase() {
+
+ private val kosmos = testKosmos()
+ private val testScope = TestScope()
+ private val sysUiState = kosmos.sysUiState
+ private val viewModel =
+ TouchpadTutorialViewModel(
+ TouchpadGesturesInteractor(sysUiState, kosmos.displayTracker, testScope.backgroundScope)
+ )
+
+ @Test
+ fun sysUiStateFlag_disabledByDefault() =
+ testScope.runTest {
+ assertThat(isFlagEnabled(SYSUI_STATE_TOUCHPAD_GESTURES_DISABLED)).isFalse()
+ }
+
+ @Test
+ fun sysUiStateFlag_enabledAfterTutorialOpened() =
+ testScope.runTest {
+ viewModel.onOpened()
+
+ assertThat(isFlagEnabled(SYSUI_STATE_TOUCHPAD_GESTURES_DISABLED)).isTrue()
+ }
+
+ @Test
+ fun sysUiStateFlag_disabledAfterTutorialClosed() =
+ testScope.runTest {
+ viewModel.onOpened()
+ viewModel.onClosed()
+
+ assertThat(isFlagEnabled(SYSUI_STATE_TOUCHPAD_GESTURES_DISABLED)).isFalse()
+ }
+
+ private fun TestScope.isFlagEnabled(@SystemUiStateFlags flag: Long): Boolean {
+ // sysui state is changed on background scope so let's make sure it's executed
+ runCurrent()
+ return sysUiState.isFlagEnabled(flag)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/tuner/TunablePaddingTest.java b/packages/SystemUI/tests/src/com/android/systemui/tuner/TunablePaddingTest.java
index 683397e..bb7b31b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/tuner/TunablePaddingTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/tuner/TunablePaddingTest.java
@@ -26,14 +26,17 @@
import android.view.View;
import android.view.WindowManager;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.utils.leaks.LeakCheckedTest;
import org.junit.Before;
import org.junit.Test;
+import org.junit.runner.RunWith;
@SmallTest
+@RunWith(AndroidJUnit4.class)
public class TunablePaddingTest extends LeakCheckedTest {
private static final String KEY = "KEY";
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/DisplaySwitchLatencyTrackerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/DisplaySwitchLatencyTrackerTest.kt
index 2cdc8d8..5d850d8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/unfold/DisplaySwitchLatencyTrackerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/DisplaySwitchLatencyTrackerTest.kt
@@ -18,7 +18,7 @@
import android.content.Context
import android.content.res.Resources
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.internal.R
import com.android.systemui.SysuiTestCase
@@ -65,7 +65,7 @@
import org.mockito.MockitoAnnotations
@OptIn(ExperimentalCoroutinesApi::class)
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
class DisplaySwitchLatencyTrackerTest : SysuiTestCase() {
private lateinit var displaySwitchLatencyTracker: DisplaySwitchLatencyTracker
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldAodAnimationControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldAodAnimationControllerTest.kt
index e1797c4..c29b86c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldAodAnimationControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldAodAnimationControllerTest.kt
@@ -19,9 +19,9 @@
import android.hardware.devicestate.DeviceStateManager
import android.hardware.devicestate.DeviceStateManager.FoldStateListener
import android.os.PowerManager
-import android.testing.AndroidTestingRunner
import android.view.ViewGroup
import android.view.ViewTreeObserver
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.internal.util.LatencyTracker
import com.android.systemui.SysuiTestCase
@@ -56,7 +56,7 @@
import org.mockito.Mockito.`when` as whenever
import org.mockito.MockitoAnnotations
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
class FoldAodAnimationControllerTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldLightRevealOverlayAnimationTest.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldLightRevealOverlayAnimationTest.kt
index dddc712..266a60d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldLightRevealOverlayAnimationTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldLightRevealOverlayAnimationTest.kt
@@ -18,11 +18,14 @@
import android.os.PowerManager
import android.os.SystemProperties
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.internal.foldables.FoldLockSettingAvailabilityProvider
+import com.android.internal.jank.Cuj.CUJ_FOLD_ANIM
+import com.android.internal.jank.InteractionJankMonitor
import com.android.systemui.SysuiTestCase
+import com.android.systemui.animation.AnimatorTestRule
import com.android.systemui.display.data.repository.DeviceStateRepository.DeviceState
import com.android.systemui.display.data.repository.fakeDeviceStateRepository
import com.android.systemui.kosmos.Kosmos
@@ -32,27 +35,34 @@
import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setScreenPowerState
import com.android.systemui.power.domain.interactor.powerInteractor
import com.android.systemui.power.shared.model.ScreenPowerState
+import com.android.systemui.statusbar.LightRevealScrim
import com.android.systemui.util.animation.data.repository.fakeAnimationStatusRepository
-import com.android.systemui.util.mockito.any
-import com.android.systemui.util.mockito.mock
-import com.android.systemui.util.mockito.whenever
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.advanceTimeBy
import kotlinx.coroutines.test.runTest
import org.junit.Before
+import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mockito.atLeast
import org.mockito.Mockito.never
+import org.mockito.Mockito.times
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
+import org.mockito.kotlin.any
+import org.mockito.kotlin.clearInvocations
+import org.mockito.kotlin.eq
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.whenever
@SmallTest
@TestableLooper.RunWithLooper(setAsMainLooper = true)
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@OptIn(ExperimentalCoroutinesApi::class)
class FoldLightRevealOverlayAnimationTest : SysuiTestCase() {
+ @get:Rule val animatorTestRule = AnimatorTestRule(this)
+
private val kosmos = Kosmos()
private val testScope: TestScope = kosmos.testScope
private val fakeDeviceStateRepository = kosmos.fakeDeviceStateRepository
@@ -63,6 +73,8 @@
private val mockFoldLockSettingAvailabilityProvider =
mock<FoldLockSettingAvailabilityProvider>()
private val onOverlayReady = mock<Runnable>()
+ private val mockJankMonitor = mock<InteractionJankMonitor>()
+ private val mockScrimView = mock<LightRevealScrim>()
private lateinit var foldLightRevealAnimation: FoldLightRevealOverlayAnimation
@Before
@@ -71,6 +83,8 @@
whenever(mockFoldLockSettingAvailabilityProvider.isFoldLockBehaviorAvailable)
.thenReturn(true)
fakeAnimationStatusRepository.onAnimationStatusChanged(true)
+ whenever(mockFullScreenController.scrimView).thenReturn(mockScrimView)
+ whenever(mockJankMonitor.begin(any(), eq(CUJ_FOLD_ANIM))).thenReturn(true)
foldLightRevealAnimation =
FoldLightRevealOverlayAnimation(
@@ -80,7 +94,8 @@
testScope.backgroundScope,
fakeAnimationStatusRepository,
mockControllerFactory,
- mockFoldLockSettingAvailabilityProvider
+ mockFoldLockSettingAvailabilityProvider,
+ mockJankMonitor
)
foldLightRevealAnimation.init()
}
@@ -99,9 +114,9 @@
testScope.runTest {
foldDeviceToScreenOff()
emitLastWakefulnessEventStartingToSleep()
- advanceTimeBy(SHORT_DELAY_MS)
+ advanceTime(SHORT_DELAY_MS)
turnScreenOn()
- advanceTimeBy(ANIMATION_DURATION)
+ advanceTime(ANIMATION_DURATION)
verifyFoldAnimationDidNotPlay()
}
@@ -111,8 +126,8 @@
testScope.runTest {
foldDeviceToScreenOff()
emitLastWakefulnessEventStartingToSleep()
- advanceTimeBy(SHORT_DELAY_MS)
- advanceTimeBy(ANIMATION_DURATION)
+ advanceTime(SHORT_DELAY_MS)
+ advanceTime(ANIMATION_DURATION)
verifyFoldAnimationDidNotPlay()
}
@@ -122,10 +137,10 @@
testScope.runTest {
foldDeviceToScreenOff()
foldLightRevealAnimation.onScreenTurningOn {}
- advanceTimeBy(WAIT_FOR_ANIMATION_TIMEOUT_MS)
+ advanceTime(WAIT_FOR_ANIMATION_TIMEOUT_MS)
powerInteractor.setScreenPowerState(ScreenPowerState.SCREEN_ON)
- advanceTimeBy(SHORT_DELAY_MS)
- advanceTimeBy(ANIMATION_DURATION)
+ advanceTime(SHORT_DELAY_MS)
+ advanceTime(ANIMATION_DURATION)
verifyFoldAnimationDidNotPlay()
}
@@ -135,10 +150,12 @@
testScope.runTest {
foldDeviceToScreenOff()
foldLightRevealAnimation.onScreenTurningOn {}
- advanceTimeBy(SHORT_DELAY_MS)
- advanceTimeBy(ANIMATION_DURATION)
+ advanceTime(SHORT_DELAY_MS)
+ clearInvocations(mockFullScreenController)
+
+ // Unfold the device
fakeDeviceStateRepository.emit(DeviceState.HALF_FOLDED)
- advanceTimeBy(SHORT_DELAY_MS)
+ advanceTime(SHORT_DELAY_MS)
powerInteractor.setScreenPowerState(ScreenPowerState.SCREEN_ON)
verifyOverlayWasRemoved()
@@ -149,12 +166,38 @@
testScope.runTest {
foldDeviceToScreenOff()
turnScreenOn()
- advanceTimeBy(ANIMATION_DURATION)
+ clearInvocations(mockFullScreenController)
+ advanceTime(ANIMATION_DURATION)
verifyOverlayWasRemoved()
}
@Test
+ fun foldToScreenOn_jankCujIsStarted() =
+ testScope.runTest {
+ foldDeviceToScreenOff()
+ turnScreenOn()
+ // Cuj has started but not ended
+ verify(mockJankMonitor, times(1)).begin(any(), eq(CUJ_FOLD_ANIM))
+ verify(mockJankMonitor, never()).end(eq(CUJ_FOLD_ANIM))
+ }
+
+ @Test
+ fun foldToScreenOn_animationFinished_jankCujIsFinished() =
+ testScope.runTest {
+ foldDeviceToScreenOff()
+ turnScreenOn()
+
+ advanceTime(ANIMATION_DURATION)
+ verify(mockJankMonitor, times(1)).end(eq(CUJ_FOLD_ANIM))
+ }
+
+ private fun TestScope.advanceTime(timeMs: Long) {
+ animatorTestRule.advanceTimeBy(timeMs)
+ advanceTimeBy(timeMs)
+ }
+
+ @Test
fun unfold_immediatelyRunRunnable() =
testScope.runTest {
foldLightRevealAnimation.onScreenTurningOn(onOverlayReady)
@@ -165,18 +208,18 @@
private suspend fun TestScope.foldDeviceToScreenOff() {
fakeDeviceStateRepository.emit(DeviceState.HALF_FOLDED)
powerInteractor.setScreenPowerState(ScreenPowerState.SCREEN_ON)
- advanceTimeBy(SHORT_DELAY_MS)
+ advanceTime(SHORT_DELAY_MS)
fakeDeviceStateRepository.emit(DeviceState.FOLDED)
- advanceTimeBy(SHORT_DELAY_MS)
+ advanceTime(SHORT_DELAY_MS)
powerInteractor.setScreenPowerState(ScreenPowerState.SCREEN_OFF)
- advanceTimeBy(SHORT_DELAY_MS)
+ advanceTime(SHORT_DELAY_MS)
}
private fun TestScope.turnScreenOn() {
foldLightRevealAnimation.onScreenTurningOn {}
- advanceTimeBy(SHORT_DELAY_MS)
+ advanceTime(SHORT_DELAY_MS)
powerInteractor.setScreenPowerState(ScreenPowerState.SCREEN_ON)
- advanceTimeBy(SHORT_DELAY_MS)
+ advanceTime(SHORT_DELAY_MS)
}
private fun emitLastWakefulnessEventStartingToSleep() =
@@ -195,6 +238,7 @@
const val WAIT_FOR_ANIMATION_TIMEOUT_MS = 2000L
val ANIMATION_DURATION: Long
get() = SystemProperties.getLong("persist.fold_animation_duration", 200L)
+
const val SHORT_DELAY_MS = 50L
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldStateLoggingProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldStateLoggingProviderTest.kt
index 39e4e64..459b3e0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldStateLoggingProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldStateLoggingProviderTest.kt
@@ -16,7 +16,7 @@
package com.android.systemui.unfold
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.unfold.FoldStateLoggingProvider.FoldStateLoggingListener
@@ -34,7 +34,7 @@
import org.junit.runner.RunWith
import org.mockito.MockitoAnnotations
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
class FoldStateLoggingProviderTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldStateRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldStateRepositoryTest.kt
index ab779a7..448b63e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldStateRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldStateRepositoryTest.kt
@@ -15,7 +15,7 @@
*/
package com.android.systemui.unfold
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
@@ -38,7 +38,7 @@
import org.junit.runner.RunWith
import org.mockito.Mockito.verify
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
class FoldStateRepositoryTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/UnfoldHapticsPlayerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/UnfoldHapticsPlayerTest.kt
index 06f1a88..208e39c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/unfold/UnfoldHapticsPlayerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/UnfoldHapticsPlayerTest.kt
@@ -18,7 +18,7 @@
import android.os.VibrationAttributes
import android.os.VibrationEffect
import android.os.vibrator
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.testKosmos
@@ -30,7 +30,7 @@
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
class UnfoldHapticsPlayerTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/UnfoldLatencyTrackerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/UnfoldLatencyTrackerTest.kt
index 2955384..1e5929d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/unfold/UnfoldLatencyTrackerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/UnfoldLatencyTrackerTest.kt
@@ -19,7 +19,7 @@
import android.hardware.devicestate.DeviceStateManager
import android.hardware.devicestate.DeviceStateManager.FoldStateListener
import android.provider.Settings
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.internal.util.LatencyTracker
import com.android.systemui.SysuiTestCase
@@ -39,7 +39,7 @@
import org.mockito.Mockito.verifyNoMoreInteractions
import org.mockito.MockitoAnnotations
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
class UnfoldLatencyTrackerTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/UnfoldTransitionWallpaperControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/UnfoldTransitionWallpaperControllerTest.kt
index 0c452eb..b5282eb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/unfold/UnfoldTransitionWallpaperControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/UnfoldTransitionWallpaperControllerTest.kt
@@ -1,6 +1,6 @@
package com.android.systemui.unfold
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.util.WallpaperController
@@ -13,7 +13,7 @@
import org.mockito.Mockito.verify
import org.mockito.junit.MockitoJUnit
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
class UnfoldTransitionWallpaperControllerTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/config/ResourceUnfoldTransitionConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/config/ResourceUnfoldTransitionConfigTest.kt
index 3c53997..b48a6da3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/unfold/config/ResourceUnfoldTransitionConfigTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/config/ResourceUnfoldTransitionConfigTest.kt
@@ -14,7 +14,7 @@
*/
package com.android.systemui.unfold.config
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.google.common.truth.Truth.assertThat
@@ -28,7 +28,7 @@
* Internal Android resource constants are not available in public APIs,
* so we can't use them there directly.
*/
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
class ResourceUnfoldTransitionConfigTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/progress/MainThreadUnfoldTransitionProgressProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/progress/MainThreadUnfoldTransitionProgressProviderTest.kt
index e5f619b..61f0abb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/unfold/progress/MainThreadUnfoldTransitionProgressProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/progress/MainThreadUnfoldTransitionProgressProviderTest.kt
@@ -19,8 +19,8 @@
import android.os.Handler
import android.os.HandlerThread
import android.os.Looper
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.unfold.FakeUnfoldTransitionProvider
@@ -29,7 +29,7 @@
import kotlinx.coroutines.test.runTest
import org.junit.runner.RunWith
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
@RunWithLooper(setAsMainLooper = true)
class MainThreadUnfoldTransitionProgressProviderTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProviderTest.kt
index 14fb054..97688d5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProviderTest.kt
@@ -17,7 +17,7 @@
import android.os.Handler
import android.os.HandlerThread
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.unfold.UnfoldTransitionProgressProvider
@@ -33,7 +33,7 @@
import org.junit.Test
import org.junit.runner.RunWith
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
class PhysicsBasedUnfoldTransitionProgressProviderTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/progress/RemoteUnfoldTransitionReceiverTest.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/progress/RemoteUnfoldTransitionReceiverTest.kt
index 4989a21..a7b67e2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/unfold/progress/RemoteUnfoldTransitionReceiverTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/progress/RemoteUnfoldTransitionReceiverTest.kt
@@ -16,7 +16,7 @@
package com.android.systemui.unfold.progress
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import androidx.test.platform.app.InstrumentationRegistry
import com.android.systemui.SysuiTestCase
@@ -24,7 +24,7 @@
import org.junit.Test
import org.junit.runner.RunWith
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
class RemoteUnfoldTransitionReceiverTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/progress/UnfoldRemoteFilterTest.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/progress/UnfoldRemoteFilterTest.kt
index 70eadce..b93c161 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/unfold/progress/UnfoldRemoteFilterTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/progress/UnfoldRemoteFilterTest.kt
@@ -16,7 +16,7 @@
package com.android.systemui.unfold.progress
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import androidx.test.platform.app.InstrumentationRegistry
import com.android.systemui.SysuiTestCase
@@ -25,7 +25,7 @@
import org.junit.Test
import org.junit.runner.RunWith
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
class UnfoldRemoteFilterTest : SysuiTestCase() {
private val listener = TestUnfoldProgressListener()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/DeviceFoldStateProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/DeviceFoldStateProviderTest.kt
index 552b60c..21a45ec 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/DeviceFoldStateProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/DeviceFoldStateProviderTest.kt
@@ -21,8 +21,8 @@
import android.content.res.Resources
import android.os.Handler
import android.os.Looper
-import android.testing.AndroidTestingRunner
import androidx.core.util.Consumer
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.unfold.config.ResourceUnfoldTransitionConfig
@@ -50,7 +50,7 @@
import org.mockito.Mockito.`when` as whenever
import org.mockito.MockitoAnnotations
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
class DeviceFoldStateProviderTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/DeviceStateRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/DeviceStateRepositoryTest.kt
index 4eb1591..4d9c80f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/DeviceStateRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/DeviceStateRepositoryTest.kt
@@ -15,7 +15,7 @@
*/
package com.android.systemui.unfold.updates
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
@@ -32,7 +32,7 @@
import org.junit.runner.RunWith
import org.mockito.Mockito.verify
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
class DeviceStateRepositoryTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/RotationChangeProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/RotationChangeProviderTest.kt
index eaef007..f5bcc21 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/RotationChangeProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/RotationChangeProviderTest.kt
@@ -21,9 +21,9 @@
import android.os.HandlerThread
import android.os.Looper
import android.os.Process
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
import android.view.Display
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.unfold.updates.RotationChangeProvider.RotationListener
@@ -41,7 +41,7 @@
import org.mockito.Mockito.verifyNoMoreInteractions
import org.mockito.MockitoAnnotations
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
@RunWithLooper
class RotationChangeProviderTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/util/NaturalRotationUnfoldProgressProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/util/NaturalRotationUnfoldProgressProviderTest.kt
index 70ec050..8d892ed 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/unfold/util/NaturalRotationUnfoldProgressProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/util/NaturalRotationUnfoldProgressProviderTest.kt
@@ -15,9 +15,9 @@
*/
package com.android.systemui.unfold.util
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.view.Surface
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.unfold.FakeUnfoldTransitionProvider
@@ -36,7 +36,7 @@
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
@TestableLooper.RunWithLooper
class NaturalRotationUnfoldProgressProviderTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/util/ScaleAwareUnfoldProgressProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/util/ScaleAwareUnfoldProgressProviderTest.kt
index 451bd24..39977c7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/unfold/util/ScaleAwareUnfoldProgressProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/util/ScaleAwareUnfoldProgressProviderTest.kt
@@ -18,8 +18,8 @@
import android.content.ContentResolver
import android.database.ContentObserver
import android.provider.Settings
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.unfold.FakeUnfoldTransitionProvider
@@ -35,7 +35,7 @@
import org.mockito.Mockito.verifyNoMoreInteractions
import org.mockito.MockitoAnnotations
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
@TestableLooper.RunWithLooper
class ScaleAwareUnfoldProgressProviderTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/util/ScopedUnfoldTransitionProgressProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/util/ScopedUnfoldTransitionProgressProviderTest.kt
index 4486402..6e0bff2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/unfold/util/ScopedUnfoldTransitionProgressProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/util/ScopedUnfoldTransitionProgressProviderTest.kt
@@ -19,8 +19,8 @@
import android.os.Handler
import android.os.HandlerThread
import android.os.Process
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.unfold.FakeUnfoldTransitionProvider
@@ -38,7 +38,7 @@
import org.junit.Test
import org.junit.runner.RunWith
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
@RunWithLooper
class ScopedUnfoldTransitionProgressProviderTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/util/UnfoldOnlyProgressProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/util/UnfoldOnlyProgressProviderTest.kt
index cd4d7b5..0cbe1ba 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/unfold/util/UnfoldOnlyProgressProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/util/UnfoldOnlyProgressProviderTest.kt
@@ -15,8 +15,8 @@
*/
package com.android.systemui.unfold.util
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.unfold.FakeUnfoldTransitionProvider
@@ -26,7 +26,7 @@
import org.junit.Test
import org.junit.runner.RunWith
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
@TestableLooper.RunWithLooper
class UnfoldOnlyProgressProviderTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/usb/UsbPermissionActivityTest.kt b/packages/SystemUI/tests/src/com/android/systemui/usb/UsbPermissionActivityTest.kt
index b04eb01..32c5986 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/usb/UsbPermissionActivityTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/usb/UsbPermissionActivityTest.kt
@@ -20,9 +20,9 @@
import android.hardware.usb.IUsbSerialReader
import android.hardware.usb.UsbAccessory
import android.hardware.usb.UsbManager
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import androidx.test.rule.ActivityTestRule
import com.android.systemui.SysuiTestCase
@@ -40,7 +40,7 @@
/**
* UsbPermissionActivityTest
*/
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
@TestableLooper.RunWithLooper
class UsbPermissionActivityTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/CreateUserActivityTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/CreateUserActivityTest.kt
index 6db35ae..84cd79d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/user/CreateUserActivityTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/user/CreateUserActivityTest.kt
@@ -1,9 +1,9 @@
package com.android.systemui.user
import android.app.Dialog
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import androidx.test.ext.junit.rules.ActivityScenarioRule
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.util.mockito.any
@@ -15,7 +15,7 @@
import org.junit.Test
import org.junit.runner.RunWith
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
@TestableLooper.RunWithLooper
class CreateUserActivityTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/UserCreatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/UserCreatorTest.kt
index 35f9c41..a291140 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/user/UserCreatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/user/UserCreatorTest.kt
@@ -3,8 +3,8 @@
import android.content.pm.UserInfo
import android.graphics.Bitmap
import android.os.UserManager
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import com.android.systemui.SysuiTestCase
import com.android.systemui.util.concurrency.FakeExecutor
@@ -22,7 +22,7 @@
import org.mockito.MockitoAnnotations
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
class UserCreatorTest : SysuiTestCase() {
companion object {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/data/repository/UserRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/data/repository/UserRepositoryImplTest.kt
index 0669cb8..37a73cf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/user/data/repository/UserRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/user/data/repository/UserRepositoryImplTest.kt
@@ -21,6 +21,7 @@
import android.os.UserHandle
import android.os.UserManager
import android.provider.Settings
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.settings.FakeUserTracker
@@ -41,7 +42,6 @@
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
import org.mockito.Mock
import org.mockito.Mockito.mock
import org.mockito.Mockito.`when` as whenever
@@ -49,7 +49,7 @@
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
-@RunWith(JUnit4::class)
+@RunWith(AndroidJUnit4::class)
class UserRepositoryImplTest : SysuiTestCase() {
@Mock private lateinit var manager: UserManager
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/GuestUserInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/GuestUserInteractorTest.kt
index 01795e9..20b273a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/GuestUserInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/GuestUserInteractorTest.kt
@@ -22,6 +22,7 @@
import android.content.pm.UserInfo
import android.os.UserHandle
import android.os.UserManager
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.internal.logging.UiEventLogger
import com.android.systemui.GuestResetOrExitSessionReceiver
@@ -39,7 +40,6 @@
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.Mock
import org.mockito.Mockito.never
@@ -47,7 +47,7 @@
import org.mockito.MockitoAnnotations
@SmallTest
-@RunWith(JUnit4::class)
+@RunWith(AndroidJUnit4::class)
class GuestUserInteractorTest : SysuiTestCase() {
@Mock private lateinit var manager: UserManager
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/RefreshUsersSchedulerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/RefreshUsersSchedulerTest.kt
index b30f77a..59ad38a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/RefreshUsersSchedulerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/RefreshUsersSchedulerTest.kt
@@ -17,6 +17,7 @@
package com.android.systemui.user.domain.interactor
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.user.data.repository.FakeUserRepository
@@ -26,11 +27,10 @@
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
import org.mockito.MockitoAnnotations
@SmallTest
-@RunWith(JUnit4::class)
+@RunWith(AndroidJUnit4::class)
class RefreshUsersSchedulerTest : SysuiTestCase() {
private lateinit var underTest: RefreshUsersScheduler
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/SelectedUserInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/SelectedUserInteractorTest.kt
index 140e919..78028f8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/SelectedUserInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/SelectedUserInteractorTest.kt
@@ -1,6 +1,7 @@
package com.android.systemui.user.domain.interactor
import android.content.pm.UserInfo
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.Flags.FLAG_REFACTOR_GET_CURRENT_USER
import com.android.systemui.SysuiTestCase
@@ -10,10 +11,9 @@
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
@SmallTest
-@RunWith(JUnit4::class)
+@RunWith(AndroidJUnit4::class)
class SelectedUserInteractorTest : SysuiTestCase() {
private lateinit var underTest: SelectedUserInteractor
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserSwitcherInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserSwitcherInteractorTest.kt
index 96c6eb8..ccbdffa 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserSwitcherInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserSwitcherInteractorTest.kt
@@ -28,6 +28,7 @@
import android.os.UserHandle
import android.os.UserManager
import android.provider.Settings
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.internal.logging.UiEventLogger
import com.android.keyguard.KeyguardUpdateMonitor
@@ -75,7 +76,6 @@
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
import org.mockito.ArgumentCaptor
import org.mockito.ArgumentMatchers.anyBoolean
import org.mockito.ArgumentMatchers.anyInt
@@ -89,7 +89,7 @@
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
-@RunWith(JUnit4::class)
+@RunWith(AndroidJUnit4::class)
class UserSwitcherInteractorTest : SysuiTestCase() {
@Mock private lateinit var activityStarter: ActivityStarter
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/StatusBarUserChipViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/StatusBarUserChipViewModelTest.kt
index 661837b..99cdf73 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/StatusBarUserChipViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/StatusBarUserChipViewModelTest.kt
@@ -23,6 +23,7 @@
import android.graphics.Bitmap
import android.graphics.drawable.BitmapDrawable
import android.os.UserManager
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.internal.logging.UiEventLogger
import com.android.keyguard.KeyguardUpdateMonitor
@@ -60,7 +61,6 @@
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.Mock
import org.mockito.Mockito.doAnswer
@@ -68,7 +68,7 @@
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
-@RunWith(JUnit4::class)
+@RunWith(AndroidJUnit4::class)
class StatusBarUserChipViewModelTest : SysuiTestCase() {
@Mock private lateinit var activityStarter: ActivityStarter
@Mock private lateinit var activityManager: ActivityManager
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt
index 5661e20..917df61 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt
@@ -21,6 +21,7 @@
import android.app.admin.DevicePolicyManager
import android.content.pm.UserInfo
import android.os.UserManager
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.internal.logging.UiEventLogger
import com.android.keyguard.KeyguardUpdateMonitor
@@ -62,13 +63,12 @@
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
import org.mockito.Mock
import org.mockito.MockitoAnnotations
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
-@RunWith(JUnit4::class)
+@RunWith(AndroidJUnit4::class)
class UserSwitcherViewModelTest : SysuiTestCase() {
@Mock private lateinit var activityStarter: ActivityStarter
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/kotlin/PackageManagerExtComponentEnabledTest.kt b/packages/SystemUI/tests/src/com/android/systemui/util/kotlin/PackageManagerExtComponentEnabledTest.kt
index 8bfff9c2..b3f2113 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/kotlin/PackageManagerExtComponentEnabledTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/kotlin/PackageManagerExtComponentEnabledTest.kt
@@ -19,6 +19,7 @@
import android.content.ComponentName
import android.content.pm.ComponentInfo
import android.content.pm.PackageManager
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.util.mockito.mock
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/AsyncSensorManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/AsyncSensorManagerTest.java
index df08efa..c896fc0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/AsyncSensorManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/AsyncSensorManagerTest.java
@@ -23,8 +23,8 @@
import static org.mockito.Mockito.verifyNoMoreInteractions;
import android.hardware.SensorEventListener;
-import android.testing.AndroidTestingRunner;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -39,7 +39,7 @@
import org.junit.runner.RunWith;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
public class AsyncSensorManagerTest extends SysuiTestCase {
private AsyncSensorManager mAsyncSensorManager;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/settings/SettingsProxyTest.kt b/packages/SystemUI/tests/src/com/android/systemui/util/settings/SettingsProxyTest.kt
index eb11e38..ef8d51a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/settings/SettingsProxyTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/settings/SettingsProxyTest.kt
@@ -22,8 +22,8 @@
import android.os.Handler
import android.os.Looper
import android.provider.Settings.SettingNotFoundException
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.google.common.truth.Truth.assertThat
@@ -36,7 +36,7 @@
import org.mockito.kotlin.eq
/** Tests for [SettingsProxy]. */
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
@TestableLooper.RunWithLooper
class SettingsProxyTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/settings/UserSettingsProxyTest.kt b/packages/SystemUI/tests/src/com/android/systemui/util/settings/UserSettingsProxyTest.kt
index 38469ee..c08ca7d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/settings/UserSettingsProxyTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/settings/UserSettingsProxyTest.kt
@@ -23,8 +23,8 @@
import android.os.Handler
import android.os.Looper
import android.provider.Settings
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.settings.FakeUserTracker
@@ -39,7 +39,7 @@
import org.mockito.kotlin.eq
/** Tests for [UserSettingsProxy]. */
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
@TestableLooper.RunWithLooper
class UserSettingsProxyTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wallpapers/data/repository/WallpaperRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/wallpapers/data/repository/WallpaperRepositoryImplTest.kt
index 7d89a55..bdecf2b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wallpapers/data/repository/WallpaperRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/wallpapers/data/repository/WallpaperRepositoryImplTest.kt
@@ -20,6 +20,7 @@
import android.app.WallpaperManager
import android.content.Intent
import android.content.pm.UserInfo
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
@@ -37,9 +38,11 @@
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
+import org.junit.runner.RunWith
@SmallTest
@OptIn(ExperimentalCoroutinesApi::class)
+@RunWith(AndroidJUnit4::class)
class WallpaperRepositoryImplTest : SysuiTestCase() {
private val testDispatcher = StandardTestDispatcher()
diff --git a/packages/SystemUI/tests/utils/src/android/view/LayoutInflaterKosmos.kt b/packages/SystemUI/tests/utils/src/android/view/LayoutInflaterKosmos.kt
index 21dea6b..2ee289b 100644
--- a/packages/SystemUI/tests/utils/src/android/view/LayoutInflaterKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/android/view/LayoutInflaterKosmos.kt
@@ -18,6 +18,8 @@
import android.content.applicationContext
import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.util.mockito.mock
var Kosmos.layoutInflater: LayoutInflater by
Kosmos.Fixture { LayoutInflater.from(applicationContext) }
+var Kosmos.mockedLayoutInflater: LayoutInflater by Kosmos.Fixture { mock<LayoutInflater>() }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java
index 8eef930..78d8abe 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java
@@ -21,7 +21,6 @@
import android.app.Instrumentation;
import android.content.Context;
import android.content.res.Resources;
-import android.os.Build;
import android.os.Handler;
import android.os.HandlerExecutor;
import android.os.Looper;
@@ -297,7 +296,7 @@
}
public static boolean isRobolectricTest() {
- return !isRavenwoodTest() && Build.FINGERPRINT.contains("robolectric");
+ return !isRavenwoodTest() && !System.getProperty("java.vm.name").equals("Dalvik");
}
protected boolean isScreenshotTest() {
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractorKosmos.kt
index f75cdd4..9236bd2 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractorKosmos.kt
@@ -20,6 +20,7 @@
import com.android.systemui.biometrics.data.repository.fingerprintPropertyRepository
import com.android.systemui.bouncer.data.repository.keyguardBouncerRepository
import com.android.systemui.deviceentry.domain.interactor.deviceEntryFingerprintAuthInteractor
+import com.android.systemui.deviceentry.shared.DeviceEntryUdfpsRefactor
import com.android.systemui.keyguard.data.repository.biometricSettingsRepository
import com.android.systemui.keyguard.domain.interactor.keyguardInteractor
import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor
@@ -28,6 +29,7 @@
import com.android.systemui.plugins.statusbar.statusBarStateController
import com.android.systemui.scene.domain.interactor.sceneInteractor
import com.android.systemui.statusbar.policy.keyguardStateController
+import com.android.systemui.util.mockito.whenever
import com.android.systemui.util.time.systemClock
val Kosmos.alternateBouncerInteractor: AlternateBouncerInteractor by
@@ -47,3 +49,24 @@
sceneInteractor = { sceneInteractor },
)
}
+
+fun Kosmos.givenCanShowAlternateBouncer() {
+ this.givenAlternateBouncerSupported()
+ this.keyguardBouncerRepository.setPrimaryShow(false)
+ this.biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(true)
+ this.biometricSettingsRepository.setIsFingerprintAuthCurrentlyAllowed(true)
+ whenever(this.keyguardUpdateMonitor.isFingerprintLockedOut).thenReturn(false)
+ whenever(this.keyguardStateController.isUnlocked).thenReturn(false)
+}
+
+fun Kosmos.givenAlternateBouncerSupported() {
+ if (DeviceEntryUdfpsRefactor.isEnabled) {
+ this.fingerprintPropertyRepository.supportsUdfps()
+ } else {
+ this.keyguardBouncerRepository.setAlternateBouncerUIAvailable(true)
+ }
+}
+
+fun Kosmos.givenCannotShowAlternateBouncer() {
+ this.biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(false)
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalPrefsRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalPrefsRepository.kt
index d3ed58b..1da1fb2 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalPrefsRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalPrefsRepository.kt
@@ -17,16 +17,28 @@
package com.android.systemui.communal.data.repository
+import android.content.pm.UserInfo
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.map
/** Fake implementation of [CommunalPrefsRepository] */
class FakeCommunalPrefsRepository : CommunalPrefsRepository {
- private val _isCtaDismissed = MutableStateFlow(false)
- override val isCtaDismissed: Flow<Boolean> = _isCtaDismissed.asStateFlow()
+ private val _isCtaDismissed = MutableStateFlow<Set<UserInfo>>(emptySet())
+ private val _isDisclaimerDismissed = MutableStateFlow<Set<UserInfo>>(emptySet())
- override suspend fun setCtaDismissedForCurrentUser() {
- _isCtaDismissed.value = true
+ override fun isCtaDismissed(user: UserInfo): Flow<Boolean> =
+ _isCtaDismissed.map { it.contains(user) }
+
+ override fun isDisclaimerDismissed(user: UserInfo): Flow<Boolean> =
+ _isDisclaimerDismissed.map { it.contains(user) }
+
+ override suspend fun setCtaDismissed(user: UserInfo) {
+ _isCtaDismissed.value = _isCtaDismissed.value.toMutableSet().apply { add(user) }
+ }
+
+ override suspend fun setDisclaimerDismissed(user: UserInfo) {
+ _isDisclaimerDismissed.value =
+ _isDisclaimerDismissed.value.toMutableSet().apply { add(user) }
}
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorKosmos.kt
index 1583d1c..b58861b 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorKosmos.kt
@@ -19,7 +19,6 @@
import android.os.userManager
import com.android.systemui.broadcast.broadcastDispatcher
import com.android.systemui.communal.data.repository.communalMediaRepository
-import com.android.systemui.communal.data.repository.communalPrefsRepository
import com.android.systemui.communal.data.repository.communalWidgetRepository
import com.android.systemui.communal.widgets.EditWidgetsActivityStarter
import com.android.systemui.flags.Flags
@@ -46,7 +45,7 @@
broadcastDispatcher = broadcastDispatcher,
communalSceneInteractor = communalSceneInteractor,
widgetRepository = communalWidgetRepository,
- communalPrefsRepository = communalPrefsRepository,
+ communalPrefsInteractor = communalPrefsInteractor,
mediaRepository = communalMediaRepository,
smartspaceRepository = smartspaceRepository,
keyguardInteractor = keyguardInteractor,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalPrefsInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalPrefsInteractorKosmos.kt
new file mode 100644
index 0000000..37563c4
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalPrefsInteractorKosmos.kt
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.communal.domain.interactor
+
+import com.android.systemui.communal.data.repository.communalPrefsRepository
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.settings.userTracker
+import com.android.systemui.user.domain.interactor.selectedUserInteractor
+import com.android.systemui.util.mockito.mock
+
+var Kosmos.communalPrefsInteractor: CommunalPrefsInteractor by
+ Kosmos.Fixture {
+ CommunalPrefsInteractor(
+ applicationCoroutineScope,
+ communalPrefsRepository,
+ selectedUserInteractor,
+ userTracker,
+ tableLogBuffer = mock()
+ )
+ }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerViewBinderKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerViewBinderKosmos.kt
new file mode 100644
index 0000000..6eb8a49
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerViewBinderKosmos.kt
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyguard.ui.binder
+
+import android.content.applicationContext
+import android.view.layoutInflater
+import android.view.mockedLayoutInflater
+import android.view.windowManager
+import com.android.systemui.biometrics.domain.interactor.fingerprintPropertyInteractor
+import com.android.systemui.biometrics.domain.interactor.udfpsOverlayInteractor
+import com.android.systemui.common.ui.domain.interactor.configurationInteractor
+import com.android.systemui.deviceentry.domain.interactor.deviceEntryUdfpsInteractor
+import com.android.systemui.deviceentry.ui.viewmodel.AlternateBouncerUdfpsAccessibilityOverlayViewModel
+import com.android.systemui.keyguard.ui.SwipeUpAnywhereGestureHandler
+import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerDependencies
+import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerMessageAreaViewModel
+import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerUdfpsIconViewModel
+import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerViewModel
+import com.android.systemui.keyguard.ui.viewmodel.DeviceEntryBackgroundViewModel
+import com.android.systemui.keyguard.ui.viewmodel.alternateBouncerViewModel
+import com.android.systemui.keyguard.ui.viewmodel.alternateBouncerWindowViewModel
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.power.domain.interactor.powerInteractor
+import com.android.systemui.statusbar.gesture.TapGestureDetector
+import com.android.systemui.util.mockito.mock
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+
+@OptIn(ExperimentalCoroutinesApi::class)
+val Kosmos.alternateBouncerViewBinder by
+ Kosmos.Fixture {
+ AlternateBouncerViewBinder(
+ applicationScope = applicationCoroutineScope,
+ alternateBouncerWindowViewModel = { alternateBouncerWindowViewModel },
+ alternateBouncerDependencies = { alternateBouncerDependencies },
+ windowManager = { windowManager },
+ layoutInflater = { mockedLayoutInflater },
+ )
+ }
+
+private val Kosmos.alternateBouncerDependencies by
+ Kosmos.Fixture {
+ AlternateBouncerDependencies(
+ viewModel = mock<AlternateBouncerViewModel>(),
+ swipeUpAnywhereGestureHandler = mock<SwipeUpAnywhereGestureHandler>(),
+ tapGestureDetector = mock<TapGestureDetector>(),
+ udfpsIconViewModel = alternateBouncerUdfpsIconViewModel,
+ udfpsAccessibilityOverlayViewModel = {
+ mock<AlternateBouncerUdfpsAccessibilityOverlayViewModel>()
+ },
+ messageAreaViewModel = mock<AlternateBouncerMessageAreaViewModel>(),
+ powerInteractor = powerInteractor,
+ )
+ }
+
+private val Kosmos.alternateBouncerUdfpsIconViewModel by
+ Kosmos.Fixture {
+ AlternateBouncerUdfpsIconViewModel(
+ context = applicationContext,
+ configurationInteractor = configurationInteractor,
+ deviceEntryUdfpsInteractor = deviceEntryUdfpsInteractor,
+ deviceEntryBackgroundViewModel = mock<DeviceEntryBackgroundViewModel>(),
+ fingerprintPropertyInteractor = fingerprintPropertyInteractor,
+ udfpsOverlayInteractor = udfpsOverlayInteractor,
+ alternateBouncerViewModel = alternateBouncerViewModel,
+ )
+ }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/data/repository/MediaFilterRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/data/repository/MediaFilterRepositoryKosmos.kt
index 690bde7..7a04aa2 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/data/repository/MediaFilterRepositoryKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/data/repository/MediaFilterRepositoryKosmos.kt
@@ -18,6 +18,7 @@
import android.content.applicationContext
import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.media.controls.util.mediaSmartspaceLogger
import com.android.systemui.statusbar.policy.configurationController
import com.android.systemui.util.time.systemClock
@@ -26,6 +27,7 @@
MediaFilterRepository(
applicationContext = applicationContext,
systemClock = systemClock,
- configurationController = configurationController
+ configurationController = configurationController,
+ smartspaceLogger = mediaSmartspaceLogger,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/util/MediaSmartspaceLoggerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/util/MediaSmartspaceLoggerKosmos.kt
new file mode 100644
index 0000000..c63dec5
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/util/MediaSmartspaceLoggerKosmos.kt
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.media.controls.util
+
+import com.android.systemui.kosmos.Kosmos
+import org.mockito.Mockito.mock
+
+var Kosmos.mediaSmartspaceLogger by Kosmos.Fixture { MediaSmartspaceLogger() }
+val Kosmos.mockMediaSmartspaceLogger by Kosmos.Fixture { mock(MediaSmartspaceLogger::class.java) }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/data/repository/FakeAudioRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/data/repository/FakeAudioRepository.kt
index 21d59f0..fcea9e7b 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/data/repository/FakeAudioRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/data/repository/FakeAudioRepository.kt
@@ -42,6 +42,7 @@
private val models: MutableMap<AudioStream, MutableStateFlow<AudioStreamModel>> = mutableMapOf()
private val lastAudibleVolumes: MutableMap<AudioStream, Int> = mutableMapOf()
+ private val deviceCategories: MutableMap<String, Int> = mutableMapOf()
private fun getAudioStreamModelState(
audioStream: AudioStream
@@ -103,4 +104,12 @@
override suspend fun setRingerMode(audioStream: AudioStream, mode: RingerMode) {
mutableRingerMode.value = mode
}
+
+ fun setBluetoothAudioDeviceCategory(bluetoothAddress: String, category: Int) {
+ deviceCategories[bluetoothAddress] = category
+ }
+
+ override suspend fun getBluetoothAudioDeviceCategory(bluetoothAddress: String): Int {
+ return deviceCategories[bluetoothAddress] ?: AudioManager.AUDIO_DEVICE_CATEGORY_UNKNOWN
+ }
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/spatial/domain/interactor/SpatialAudioComponentInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/spatial/domain/interactor/SpatialAudioComponentInteractorKosmos.kt
index 95a7b9b..6a46d56 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/spatial/domain/interactor/SpatialAudioComponentInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/spatial/domain/interactor/SpatialAudioComponentInteractorKosmos.kt
@@ -17,8 +17,10 @@
package com.android.systemui.volume.panel.component.spatial.domain.interactor
import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.backgroundCoroutineContext
import com.android.systemui.kosmos.testScope
import com.android.systemui.media.spatializerInteractor
+import com.android.systemui.volume.data.repository.audioRepository
import com.android.systemui.volume.domain.interactor.audioOutputInteractor
val Kosmos.spatialAudioComponentInteractor by
@@ -26,6 +28,8 @@
SpatialAudioComponentInteractor(
audioOutputInteractor,
spatializerInteractor,
+ audioRepository,
+ backgroundCoroutineContext,
testScope.backgroundScope,
)
}
diff --git a/proto/src/system_messages.proto b/proto/src/system_messages.proto
index 7f542d1..e8db80a 100644
--- a/proto/src/system_messages.proto
+++ b/proto/src/system_messages.proto
@@ -310,6 +310,10 @@
// Package: android
NOTE_USB_UVC = 75;
+ // Inform the user about adaptive notifications
+ // Package: com.android.systemui
+ NOTE_ADAPTIVE_NOTIFICATIONS = 76;
+
// ADD_NEW_IDS_ABOVE_THIS_LINE
// Legacy IDs with arbitrary values appear below
// Legacy IDs existed as stable non-conflicting constants prior to the O release
diff --git a/services/OWNERS b/services/OWNERS
index 3ce5ae1..69e4e24 100644
--- a/services/OWNERS
+++ b/services/OWNERS
@@ -1,7 +1,7 @@
per-file Android.bp = file:platform/build/soong:/OWNERS #{LAST_RESORT_SUGGESTION}
# art-team@ manages the system server profile
-per-file art-profile* = calin@google.com, ngeoffray@google.com, vmarko@google.com
+per-file art-profile* = file:platform/art:main:/OWNERS_boot_profile
per-file java/com/android/server/HsumBootUserInitializer.java = file:/MULTIUSER_OWNERS
diff --git a/services/accessibility/java/com/android/server/accessibility/SystemActionPerformer.java b/services/accessibility/java/com/android/server/accessibility/SystemActionPerformer.java
index 9747579..2945af5 100644
--- a/services/accessibility/java/com/android/server/accessibility/SystemActionPerformer.java
+++ b/services/accessibility/java/com/android/server/accessibility/SystemActionPerformer.java
@@ -34,6 +34,7 @@
import android.view.KeyEvent;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
+import android.view.accessibility.Flags;
import com.android.internal.R;
import com.android.internal.accessibility.util.AccessibilityUtils;
@@ -328,6 +329,18 @@
sendDownAndUpKeyEvents(KeyEvent.KEYCODE_DPAD_CENTER,
InputDevice.SOURCE_KEYBOARD | InputDevice.SOURCE_DPAD);
return true;
+ case AccessibilityService.GLOBAL_ACTION_MENU:
+ if (Flags.globalActionMenu()) {
+ sendDownAndUpKeyEvents(KeyEvent.KEYCODE_MENU,
+ InputDevice.SOURCE_KEYBOARD);
+ }
+ return true;
+ case AccessibilityService.GLOBAL_ACTION_MEDIA_PLAY_PAUSE:
+ if (Flags.globalActionMediaPlayPause()) {
+ sendDownAndUpKeyEvents(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE,
+ InputDevice.SOURCE_KEYBOARD);
+ }
+ return true;
default:
Slog.e(TAG, "Invalid action id: " + actionId);
return false;
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index 5567707..d7649dc 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -17,6 +17,7 @@
package com.android.server.appwidget;
import static android.appwidget.flags.Flags.removeAppWidgetServiceIoFromCriticalPath;
+import static android.appwidget.flags.Flags.supportResumeRestoreAfterReboot;
import static android.content.Context.KEYGUARD_SERVICE;
import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
@@ -166,6 +167,8 @@
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.atomic.AtomicLong;
+import java.util.function.BiConsumer;
+import java.util.function.Function;
import java.util.function.LongSupplier;
class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBackupProvider,
@@ -457,7 +460,7 @@
break;
case Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE:
added = true;
- // Follow through
+ // fall through
case Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE:
pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
break;
@@ -3571,6 +3574,13 @@
}
out.endTag(null, "gs");
+
+ if (supportResumeRestoreAfterReboot()
+ && mBackupRestoreController.requiresPersistenceLocked()) {
+ AppWidgetXmlUtil.writeBackupRestoreControllerState(
+ out, mBackupRestoreController.getStateLocked(userId));
+ }
+
out.endDocument();
return true;
} catch (IOException e) {
@@ -3717,6 +3727,32 @@
LoadedWidgetState loadedWidgets = new LoadedWidgetState(widget,
hostTag, providerTag);
outLoadedWidgets.add(loadedWidgets);
+ } else if (supportResumeRestoreAfterReboot()
+ && AppWidgetXmlUtil.TAG_BACKUP_RESTORE_CONTROLLER_STATE.equals(tag)) {
+ final BackupRestoreController.State s =
+ AppWidgetXmlUtil.readBackupRestoreControllerState(parser);
+ if (s == null) {
+ continue;
+ }
+ final Set<String> prunedAppsInFile = s.getPrunedApps();
+ if (prunedAppsInFile != null) {
+ final Set<String> prunedAppsInMemory = mBackupRestoreController
+ .mPrunedAppsPerUser.get(userId);
+ if (prunedAppsInMemory == null) {
+ mBackupRestoreController.mPrunedAppsPerUser.put(
+ userId, prunedAppsInFile);
+ } else {
+ prunedAppsInMemory.addAll(prunedAppsInFile);
+ }
+ }
+ loadUpdateRecords(s.getUpdatesByProvider(),
+ this::findProviderByTag,
+ mBackupRestoreController.mUpdatesByProvider::get,
+ mBackupRestoreController.mUpdatesByProvider::put);
+ loadUpdateRecords(s.getUpdatesByHost(),
+ this::findHostByTag,
+ mBackupRestoreController.mUpdatesByHost::get,
+ mBackupRestoreController.mUpdatesByHost::put);
}
}
} while (type != XmlPullParser.END_DOCUMENT);
@@ -3732,6 +3768,36 @@
return version;
}
+ private <T> void loadUpdateRecords(
+ @Nullable final SparseArray<
+ List<BackupRestoreController.RestoreUpdateRecord>> updatesOnFile,
+ @NonNull final Function<Integer, T> findKeyByTagCb,
+ @NonNull final Function<T, List<
+ BackupRestoreController.RestoreUpdateRecord>> findRecordsCb,
+ @NonNull final BiConsumer<T, List<
+ BackupRestoreController.RestoreUpdateRecord>> newRecordsCb) {
+ if (updatesOnFile == null) {
+ return;
+ }
+ for (int i = 0; i < updatesOnFile.size(); i++) {
+ final int tag = updatesOnFile.keyAt(i);
+ final List<
+ BackupRestoreController.RestoreUpdateRecord
+ > recordsOnFile = updatesOnFile.get(tag);
+ if (recordsOnFile == null || recordsOnFile.isEmpty()) {
+ continue;
+ }
+ final T key = findKeyByTagCb.apply(tag);
+ final List<BackupRestoreController.RestoreUpdateRecord> recordsInMemory =
+ findRecordsCb.apply(key);
+ if (recordsInMemory != null) {
+ recordsInMemory.addAll(recordsOnFile);
+ } else {
+ newRecordsCb.accept(key, recordsOnFile);
+ }
+ }
+ }
+
private void performUpgradeLocked(int fromVersion) {
if (fromVersion < CURRENT_VERSION) {
Slog.v(TAG, "Upgrading widget database from " + fromVersion + " to "
@@ -4674,7 +4740,7 @@
}
}
- private static final class Provider {
+ static final class Provider {
ProviderId id;
AppWidgetProviderInfo info;
@@ -4931,7 +4997,7 @@
}
}
- private static final class Host {
+ static final class Host {
HostId id;
ArrayList<Widget> widgets = new ArrayList<>();
IAppWidgetHost callbacks;
@@ -5250,10 +5316,10 @@
/**
* This class encapsulates the backup and restore logic for a user group state.
*/
- private final class BackupRestoreController {
+ final class BackupRestoreController {
private static final String TAG = "BackupRestoreController";
- private static final boolean DEBUG = true;
+ private static final boolean DEBUG = AppWidgetServiceImpl.DEBUG;
// Version of backed-up widget state.
private static final int WIDGET_STATE_VERSION = 2;
@@ -5262,16 +5328,31 @@
// a given package. Keep track of what we've done so far here; the list is
// cleared at the start of every system restore pass, but preserved through
// any install-time restore operations.
+ @GuardedBy("AppWidgetServiceImpl.this.mLock")
private final SparseArray<Set<String>> mPrunedAppsPerUser = new SparseArray<>();
- private final HashMap<Provider, ArrayList<RestoreUpdateRecord>> mUpdatesByProvider =
- new HashMap<>();
- private final HashMap<Host, ArrayList<RestoreUpdateRecord>> mUpdatesByHost =
- new HashMap<>();
+ @GuardedBy("AppWidgetServiceImpl.this.mLock")
+ final Map<Provider, List<RestoreUpdateRecord>> mUpdatesByProvider =
+ new ArrayMap<>();
- @GuardedBy("mLock")
+ @GuardedBy("AppWidgetServiceImpl.this.mLock")
+ private final Map<Host, List<RestoreUpdateRecord>> mUpdatesByHost =
+ new ArrayMap<>();
+
+ @GuardedBy("AppWidgetServiceImpl.this.mLock")
private boolean mHasSystemRestoreFinished;
+ @GuardedBy("AppWidgetServiceImpl.this.mLock")
+ public boolean requiresPersistenceLocked() {
+ if (mHasSystemRestoreFinished) {
+ // No need to persist intermediate states if system restore is already finished.
+ return false;
+ }
+ // If either of the internal states is non-empty, then we need to persist that
+ return !(mPrunedAppsPerUser.size() == 0 && mUpdatesByProvider.isEmpty()
+ && mUpdatesByHost.isEmpty());
+ }
+
public List<String> getWidgetParticipants(int userId) {
if (DEBUG) {
Slog.i(TAG, "Getting widget participants for user: " + userId);
@@ -5436,7 +5517,7 @@
// If there's no live entry for this provider, add an inactive one
// so that widget IDs referring to them can be properly allocated
- // Backup and resotre only for the parent profile.
+ // Backup and restore only for the parent profile.
ComponentName componentName = new ComponentName(pkg, cl);
Provider p = findProviderLocked(componentName, userId);
@@ -5579,9 +5660,9 @@
final UserHandle userHandle = new UserHandle(userId);
// Build the providers' broadcasts and send them off
- Set<Map.Entry<Provider, ArrayList<RestoreUpdateRecord>>> providerEntries
+ Set<Map.Entry<Provider, List<RestoreUpdateRecord>>> providerEntries
= mUpdatesByProvider.entrySet();
- for (Map.Entry<Provider, ArrayList<RestoreUpdateRecord>> e : providerEntries) {
+ for (Map.Entry<Provider, List<RestoreUpdateRecord>> e : providerEntries) {
// For each provider there's a list of affected IDs
Provider provider = e.getKey();
if (provider.zombie) {
@@ -5589,7 +5670,7 @@
// We'll be called again when the provider is installed.
continue;
}
- ArrayList<RestoreUpdateRecord> updates = e.getValue();
+ List<RestoreUpdateRecord> updates = e.getValue();
final int pending = countPendingUpdates(updates);
if (DEBUG) {
Slog.i(TAG, "Provider " + provider + " pending: " + pending);
@@ -5618,12 +5699,12 @@
}
// same thing per host
- Set<Map.Entry<Host, ArrayList<RestoreUpdateRecord>>> hostEntries
+ Set<Map.Entry<Host, List<RestoreUpdateRecord>>> hostEntries
= mUpdatesByHost.entrySet();
- for (Map.Entry<Host, ArrayList<RestoreUpdateRecord>> e : hostEntries) {
+ for (Map.Entry<Host, List<RestoreUpdateRecord>> e : hostEntries) {
Host host = e.getKey();
if (host.id.uid != UNKNOWN_UID) {
- ArrayList<RestoreUpdateRecord> updates = e.getValue();
+ List<RestoreUpdateRecord> updates = e.getValue();
final int pending = countPendingUpdates(updates);
if (DEBUG) {
Slog.i(TAG, "Host " + host + " pending: " + pending);
@@ -5714,8 +5795,9 @@
return false;
}
+ @GuardedBy("mLock")
private void stashProviderRestoreUpdateLocked(Provider provider, int oldId, int newId) {
- ArrayList<RestoreUpdateRecord> r = mUpdatesByProvider.get(provider);
+ List<RestoreUpdateRecord> r = mUpdatesByProvider.get(provider);
if (r == null) {
r = new ArrayList<>();
mUpdatesByProvider.put(provider, r);
@@ -5732,7 +5814,7 @@
r.add(new RestoreUpdateRecord(oldId, newId));
}
- private boolean alreadyStashed(ArrayList<RestoreUpdateRecord> stash,
+ private boolean alreadyStashed(List<RestoreUpdateRecord> stash,
final int oldId, final int newId) {
final int N = stash.size();
for (int i = 0; i < N; i++) {
@@ -5744,8 +5826,9 @@
return false;
}
+ @GuardedBy("mLock")
private void stashHostRestoreUpdateLocked(Host host, int oldId, int newId) {
- ArrayList<RestoreUpdateRecord> r = mUpdatesByHost.get(host);
+ List<RestoreUpdateRecord> r = mUpdatesByHost.get(host);
if (r == null) {
r = new ArrayList<>();
mUpdatesByHost.put(host, r);
@@ -5835,7 +5918,7 @@
|| widget.provider.getUserId() == userId);
}
- private int countPendingUpdates(ArrayList<RestoreUpdateRecord> updates) {
+ private int countPendingUpdates(List<RestoreUpdateRecord> updates) {
int pending = 0;
final int N = updates.size();
for (int i = 0; i < N; i++) {
@@ -5847,9 +5930,28 @@
return pending;
}
+ @GuardedBy("mLock")
+ @NonNull
+ private State getStateLocked(final int userId) {
+ final Set<String> prunedApps = mPrunedAppsPerUser.get(userId);
+ final SparseArray<List<RestoreUpdateRecord>> updatesByProvider = new SparseArray<>();
+ final SparseArray<List<RestoreUpdateRecord>> updatesByHost = new SparseArray<>();
+ mUpdatesByProvider.forEach((p, updates) -> {
+ if (p.getUserId() == userId) {
+ updatesByProvider.put(p.tag, new ArrayList<>(updates));
+ }
+ });
+ mUpdatesByHost.forEach((h, updates) -> {
+ if (h.getUserId() == userId) {
+ updatesByHost.put(h.tag, new ArrayList<>(updates));
+ }
+ });
+ return new State(prunedApps, updatesByProvider, updatesByHost);
+ }
+
// Accumulate a list of updates that affect the given provider for a final
// coalesced notification broadcast once restore is over.
- private class RestoreUpdateRecord {
+ static class RestoreUpdateRecord {
public int oldId;
public int newId;
public boolean notified;
@@ -5860,6 +5962,45 @@
notified = false;
}
}
+
+ static final class State {
+ // We need to make sure to wipe the pre-restore widget state only once for
+ // a given package. Keep track of what we've done so far here; the list is
+ // cleared at the start of every system restore pass, but preserved through
+ // any install-time restore operations.
+ @Nullable
+ private final Set<String> mPrunedApps;
+
+ @Nullable
+ private final SparseArray<List<RestoreUpdateRecord>> mUpdatesByProvider;
+
+ @Nullable
+ private final SparseArray<List<RestoreUpdateRecord>> mUpdatesByHost;
+
+ State(
+ @Nullable final Set<String> prunedApps,
+ @Nullable final SparseArray<List<RestoreUpdateRecord>> updatesByProvider,
+ @Nullable final SparseArray<List<RestoreUpdateRecord>> updatesByHost) {
+ mPrunedApps = prunedApps;
+ mUpdatesByProvider = updatesByProvider;
+ mUpdatesByHost = updatesByHost;
+ }
+
+ @Nullable
+ Set<String> getPrunedApps() {
+ return mPrunedApps;
+ }
+
+ @Nullable
+ SparseArray<List<BackupRestoreController.RestoreUpdateRecord>> getUpdatesByProvider() {
+ return mUpdatesByProvider;
+ }
+
+ @Nullable
+ SparseArray<List<BackupRestoreController.RestoreUpdateRecord>> getUpdatesByHost() {
+ return mUpdatesByHost;
+ }
+ }
}
private class AppWidgetManagerLocal extends AppWidgetManagerInternal {
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetXmlUtil.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetXmlUtil.java
index d781cd8..ce9130a 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetXmlUtil.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetXmlUtil.java
@@ -22,17 +22,24 @@
import android.content.ComponentName;
import android.os.Build;
import android.text.TextUtils;
+import android.util.ArraySet;
+import android.util.Log;
import android.util.SizeF;
import android.util.Slog;
+import android.util.SparseArray;
import com.android.modules.utils.TypedXmlPullParser;
import com.android.modules.utils.TypedXmlSerializer;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
+import java.util.Set;
import java.util.stream.Collectors;
/**
@@ -65,6 +72,16 @@
private static final String ATTR_DESCRIPTION_RES = "description_res";
private static final String ATTR_PROVIDER_INHERITANCE = "provider_inheritance";
private static final String ATTR_OS_FINGERPRINT = "os_fingerprint";
+ static final String TAG_BACKUP_RESTORE_CONTROLLER_STATE = "br";
+ private static final String TAG_PRUNED_APPS = "pruned_apps";
+ private static final String ATTR_TAG = "tag";
+ private static final String ATTR_PACKAGE_NAMES = "pkgs";
+ private static final String TAG_PROVIDER_UPDATES = "provider_updates";
+ private static final String TAG_HOST_UPDATES = "host_updates";
+ private static final String TAG_RECORD = "record";
+ private static final String ATTR_OLD_ID = "old_id";
+ private static final String ATTR_NEW_ID = "new_id";
+ private static final String ATTR_NOTIFIED = "notified";
private static final String SIZE_SEPARATOR = ",";
/**
@@ -165,4 +182,168 @@
return null;
}
}
+
+ /**
+ * Persists {@link AppWidgetServiceImpl.BackupRestoreController.State} to disk as XML.
+ * See {@link #readBackupRestoreControllerState(TypedXmlPullParser)} for example XML.
+ *
+ * @param out XML serializer
+ * @param state {@link AppWidgetServiceImpl.BackupRestoreController.State} of
+ * intermediate states to be persisted as xml to resume restore after reboot.
+ */
+ static void writeBackupRestoreControllerState(
+ @NonNull final TypedXmlSerializer out,
+ @NonNull final AppWidgetServiceImpl.BackupRestoreController.State state)
+ throws IOException {
+ Objects.requireNonNull(out);
+ Objects.requireNonNull(state);
+ out.startTag(null, TAG_BACKUP_RESTORE_CONTROLLER_STATE);
+ final Set<String> prunedApps = state.getPrunedApps();
+ if (prunedApps != null && !prunedApps.isEmpty()) {
+ out.startTag(null, TAG_PRUNED_APPS);
+ out.attribute(null, ATTR_PACKAGE_NAMES, String.join(",", prunedApps));
+ out.endTag(null, TAG_PRUNED_APPS);
+ }
+ final SparseArray<List<AppWidgetServiceImpl.BackupRestoreController.RestoreUpdateRecord>>
+ updatesByProvider = state.getUpdatesByProvider();
+ if (updatesByProvider != null) {
+ writeUpdateRecords(out, TAG_PROVIDER_UPDATES, updatesByProvider);
+ }
+ final SparseArray<List<AppWidgetServiceImpl.BackupRestoreController.RestoreUpdateRecord>>
+ updatesByHost = state.getUpdatesByHost();
+ if (updatesByHost != null) {
+ writeUpdateRecords(out, TAG_HOST_UPDATES, updatesByHost);
+ }
+ out.endTag(null, TAG_BACKUP_RESTORE_CONTROLLER_STATE);
+ }
+
+ private static void writeUpdateRecords(@NonNull final TypedXmlSerializer out,
+ @NonNull final String outerTag, @NonNull final SparseArray<List<
+ AppWidgetServiceImpl.BackupRestoreController.RestoreUpdateRecord>> records)
+ throws IOException {
+ for (int i = 0; i < records.size(); i++) {
+ final int tag = records.keyAt(i);
+ out.startTag(null, outerTag);
+ out.attributeInt(null, ATTR_TAG, tag);
+ final List<AppWidgetServiceImpl.BackupRestoreController.RestoreUpdateRecord> entries =
+ records.get(tag);
+ for (AppWidgetServiceImpl.BackupRestoreController.RestoreUpdateRecord entry : entries) {
+ out.startTag(null, TAG_RECORD);
+ out.attributeInt(null, ATTR_OLD_ID, entry.oldId);
+ out.attributeInt(null, ATTR_NEW_ID, entry.newId);
+ out.attributeBoolean(null, ATTR_NOTIFIED, entry.notified);
+ out.endTag(null, TAG_RECORD);
+ }
+ out.endTag(null, outerTag);
+ }
+ }
+
+ /**
+ * Parses {@link AppWidgetServiceImpl.BackupRestoreController.State} from xml.
+ *
+ * <pre>
+ * {@code
+ * <?xml version="1.0"?>
+ * <br>
+ * <pruned_apps pkgs="com.example.app1,com.example.app2,com.example.app3" />
+ * <provider_updates tag="0">
+ * <record old_id="10" new_id="0" notified="false" />
+ * </provider_updates>
+ * <provider_updates tag="1">
+ * <record old_id="9" new_id="1" notified="true" />
+ * </provider_updates>
+ * <provider_updates tag="2">
+ * <record old_id="8" new_id="2" notified="false" />
+ * </provider_updates>
+ * <host_updates tag="0">
+ * <record old_id="10" new_id="0" notified="false" />
+ * </host_updates>
+ * <host_updates tag="1">
+ * <record old_id="9" new_id="1" notified="true" />
+ * </host_updates>
+ * <host_updates tag="2">
+ * <record old_id="8" new_id="2" notified="false" />
+ * </host_updates>
+ * </br>
+ * }
+ * </pre>
+ *
+ * @param parser XML parser
+ * @return {@link AppWidgetServiceImpl.BackupRestoreController.State} of intermediate states
+ * in {@link AppWidgetServiceImpl.BackupRestoreController}, so that backup & restore can be
+ * resumed after reboot.
+ */
+ @Nullable
+ static AppWidgetServiceImpl.BackupRestoreController.State
+ readBackupRestoreControllerState(@NonNull final TypedXmlPullParser parser) {
+ Objects.requireNonNull(parser);
+ int type;
+ String tag = null;
+ final Set<String> prunedApps = new ArraySet<>(1);
+ final SparseArray<List<AppWidgetServiceImpl.BackupRestoreController.RestoreUpdateRecord>>
+ updatesByProviders = new SparseArray<>();
+ final SparseArray<List<AppWidgetServiceImpl.BackupRestoreController.RestoreUpdateRecord>>
+ updatesByHosts = new SparseArray<>();
+
+ try {
+ do {
+ type = parser.next();
+ if (type != XmlPullParser.START_TAG) {
+ continue;
+ }
+ tag = parser.getName();
+ switch (tag) {
+ case TAG_PRUNED_APPS:
+ final String packages =
+ parser.getAttributeValue(null, ATTR_PACKAGE_NAMES);
+ prunedApps.addAll(Arrays.asList(packages.split(",")));
+ break;
+ case TAG_PROVIDER_UPDATES:
+ updatesByProviders.put(parser.getAttributeInt(null, ATTR_TAG),
+ parseRestoreUpdateRecords(parser));
+ break;
+ case TAG_HOST_UPDATES:
+ updatesByHosts.put(parser.getAttributeInt(null, ATTR_TAG),
+ parseRestoreUpdateRecords(parser));
+ break;
+ default:
+ break;
+ }
+ } while (type != XmlPullParser.END_DOCUMENT
+ && (!TAG_BACKUP_RESTORE_CONTROLLER_STATE.equals(tag)
+ || type != XmlPullParser.END_TAG));
+ } catch (IOException | XmlPullParserException e) {
+ Log.e(TAG, "error parsing state", e);
+ return null;
+ }
+ return new AppWidgetServiceImpl.BackupRestoreController.State(
+ prunedApps, updatesByProviders, updatesByHosts);
+ }
+
+ @NonNull
+ private static List<
+ AppWidgetServiceImpl.BackupRestoreController.RestoreUpdateRecord
+ > parseRestoreUpdateRecords(@NonNull final TypedXmlPullParser parser)
+ throws XmlPullParserException, IOException {
+ int type;
+ String tag;
+ final List<AppWidgetServiceImpl.BackupRestoreController.RestoreUpdateRecord> ret =
+ new ArrayList<>();
+ do {
+ type = parser.next();
+ tag = parser.getName();
+ if (tag.equals(TAG_RECORD) && type == XmlPullParser.START_TAG) {
+ final int oldId = parser.getAttributeInt(null, ATTR_OLD_ID);
+ final int newId = parser.getAttributeInt(null, ATTR_NEW_ID);
+ final boolean notified = parser.getAttributeBoolean(
+ null, ATTR_NOTIFIED);
+ final AppWidgetServiceImpl.BackupRestoreController.RestoreUpdateRecord record =
+ new AppWidgetServiceImpl.BackupRestoreController.RestoreUpdateRecord(
+ oldId, newId);
+ record.notified = notified;
+ ret.add(record);
+ }
+ } while (tag.equals(TAG_RECORD));
+ return ret;
+ }
}
diff --git a/services/companion/java/com/android/server/companion/association/AssociationRequestsProcessor.java b/services/companion/java/com/android/server/companion/association/AssociationRequestsProcessor.java
index 3fbd856..b3a2da4 100644
--- a/services/companion/java/com/android/server/companion/association/AssociationRequestsProcessor.java
+++ b/services/companion/java/com/android/server/companion/association/AssociationRequestsProcessor.java
@@ -19,7 +19,6 @@
import static android.app.PendingIntent.FLAG_CANCEL_CURRENT;
import static android.app.PendingIntent.FLAG_IMMUTABLE;
import static android.app.PendingIntent.FLAG_ONE_SHOT;
-import static android.companion.CompanionDeviceManager.REASON_INTERNAL_ERROR;
import static android.companion.CompanionDeviceManager.RESULT_INTERNAL_ERROR;
import static android.content.ComponentName.createRelative;
import static android.content.pm.PackageManager.FEATURE_WATCH;
@@ -183,7 +182,7 @@
String errorMessage = "3p apps are not allowed to create associations on watch.";
Slog.e(TAG, errorMessage);
try {
- callback.onFailure(errorMessage);
+ callback.onFailure(RESULT_INTERNAL_ERROR);
} catch (RemoteException e) {
// ignored
}
@@ -252,8 +251,9 @@
} catch (SecurityException e) {
// Since, at this point the caller is our own UI, we need to catch the exception on
// forward it back to the application via the callback.
+ Slog.e(TAG, e.getMessage());
try {
- callback.onFailure(e.getMessage());
+ callback.onFailure(RESULT_INTERNAL_ERROR);
} catch (RemoteException ignore) {
}
return;
@@ -378,7 +378,7 @@
// Send the association back via the app's callback
if (callback != null) {
try {
- callback.onFailure(REASON_INTERNAL_ERROR);
+ callback.onFailure(RESULT_INTERNAL_ERROR);
} catch (RemoteException ignore) {
}
}
diff --git a/services/companion/java/com/android/server/companion/virtual/CameraAccessController.java b/services/companion/java/com/android/server/companion/virtual/CameraAccessController.java
index ce4067c..ef39846 100644
--- a/services/companion/java/com/android/server/companion/virtual/CameraAccessController.java
+++ b/services/companion/java/com/android/server/companion/virtual/CameraAccessController.java
@@ -192,7 +192,8 @@
for (UserInfo user : aliveUsers) {
int userId = user.getUserHandle().getIdentifier();
int appUid = queryUidFromPackageName(userId, packageName);
- if (mVirtualDeviceManagerInternal.isAppRunningOnAnyVirtualDevice(appUid)) {
+ if (mVirtualDeviceManagerInternal != null
+ && mVirtualDeviceManagerInternal.isAppRunningOnAnyVirtualDevice(appUid)) {
if (data == null) {
data = new InjectionSessionData();
data.appUid = appUid;
diff --git a/services/companion/java/com/android/server/companion/virtual/SensorController.java b/services/companion/java/com/android/server/companion/virtual/SensorController.java
index cf48180..0655685 100644
--- a/services/companion/java/com/android/server/companion/virtual/SensorController.java
+++ b/services/companion/java/com/android/server/companion/virtual/SensorController.java
@@ -229,6 +229,10 @@
Slog.e(TAG, "No sensor callback configured for sensor handle " + handle);
return BAD_VALUE;
}
+ if (mVdmInternal == null) {
+ Slog.e(TAG, "Virtual Device Manager is not enabled.");
+ return BAD_VALUE;
+ }
VirtualSensor sensor = mVdmInternal.getVirtualSensor(mVirtualDeviceId, handle);
if (sensor == null) {
Slog.e(TAG, "No sensor found for deviceId=" + mVirtualDeviceId
@@ -285,6 +289,10 @@
Slog.e(TAG, "No runtime sensor callback configured.");
return BAD_VALUE;
}
+ if (mVdmInternal == null) {
+ Slog.e(TAG, "Virtual Device Manager is not enabled.");
+ return BAD_VALUE;
+ }
VirtualSensor sensor = mVdmInternal.getVirtualSensor(mVirtualDeviceId, sensorHandle);
if (sensor == null) {
Slog.e(TAG, "No sensor found for deviceId=" + mVirtualDeviceId
diff --git a/services/core/java/com/android/server/EventLogTags.logtags b/services/core/java/com/android/server/EventLogTags.logtags
index 256f2b3..361b818 100644
--- a/services/core/java/com/android/server/EventLogTags.logtags
+++ b/services/core/java/com/android/server/EventLogTags.logtags
@@ -63,7 +63,7 @@
# NotificationManagerService.java
# ---------------------------
# when a NotificationManager.notify is called. status: 0=post, 1=update, 2=ignored
-2750 notification_enqueue (uid|1|5),(pid|1|5),(pkg|3),(id|1|5),(tag|3),(userid|1|5),(notification|3),(status|1)
+2750 notification_enqueue (uid|1|5),(pid|1|5),(pkg|3),(id|1|5),(tag|3),(userid|1|5),(notification|3),(status|1),(app_provided|1)
# when someone tries to cancel a notification, the notification manager sometimes
# calls this with flags too
2751 notification_cancel (uid|1|5),(pid|1|5),(pkg|3),(id|1|5),(tag|3),(userid|1|5),(required_flags|1),(forbidden_flags|1),(reason|1|5),(listener|3)
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 022df9a..195e94b 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -10235,19 +10235,6 @@
addStartInfoTimestampInternal(key, timestampNs, userId, callingUid);
}
- @Override
- public void reportStartInfoViewTimestamps(long renderThreadDrawStartTimeNs,
- long framePresentedTimeNs) {
- int callingUid = Binder.getCallingUid();
- int userId = UserHandle.getUserId(callingUid);
- addStartInfoTimestampInternal(
- ApplicationStartInfo.START_TIMESTAMP_INITIAL_RENDERTHREAD_FRAME,
- renderThreadDrawStartTimeNs, userId, callingUid);
- addStartInfoTimestampInternal(
- ApplicationStartInfo.START_TIMESTAMP_SURFACEFLINGER_COMPOSITION_COMPLETE,
- framePresentedTimeNs, userId, callingUid);
- }
-
private void addStartInfoTimestampInternal(int key, long timestampNs, int userId, int uid) {
mProcessList.getAppStartInfoTracker().addTimestampToStart(
Settings.getPackageNameForUid(mContext, uid),
diff --git a/services/core/java/com/android/server/am/AppExitInfoTracker.java b/services/core/java/com/android/server/am/AppExitInfoTracker.java
index 666e560..47b65eb 100644
--- a/services/core/java/com/android/server/am/AppExitInfoTracker.java
+++ b/services/core/java/com/android/server/am/AppExitInfoTracker.java
@@ -88,6 +88,7 @@
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Consumer;
+import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.zip.GZIPOutputStream;
@@ -104,9 +105,9 @@
private static final long APP_EXIT_INFO_PERSIST_INTERVAL = TimeUnit.MINUTES.toMillis(30);
/** These are actions that the forEach* should take after each iteration */
- private static final int FOREACH_ACTION_NONE = 0;
- private static final int FOREACH_ACTION_REMOVE_ITEM = 1;
- private static final int FOREACH_ACTION_STOP_ITERATION = 2;
+ @VisibleForTesting static final int FOREACH_ACTION_NONE = 0;
+ @VisibleForTesting static final int FOREACH_ACTION_REMOVE_ITEM = 1;
+ @VisibleForTesting static final int FOREACH_ACTION_STOP_ITERATION = 2;
private static final int APP_EXIT_RAW_INFO_POOL_SIZE = 8;
@@ -125,7 +126,7 @@
private static final String APP_TRACE_FILE_SUFFIX = ".gz";
- private final Object mLock = new Object();
+ @VisibleForTesting final Object mLock = new Object();
/**
* Initialized in {@link #init} and read-only after that.
@@ -410,6 +411,23 @@
}
/**
+ * Certain types of crashes should not be updated. This could end up deleting valuable
+ * information, for example, if a test application crashes and then the `am instrument`
+ * finishes, then the crash whould be replaced with a `reason == USER_REQUESTED`
+ * ApplicationExitInfo from ActivityManager, and the original crash would be lost.
+ */
+ private boolean preventExitInfoUpdate(final ApplicationExitInfo exitInfo) {
+ switch (exitInfo.getReason()) {
+ case ApplicationExitInfo.REASON_ANR:
+ case ApplicationExitInfo.REASON_CRASH:
+ case ApplicationExitInfo.REASON_CRASH_NATIVE:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ /**
* Make note when ActivityManagerService decides to kill an application process.
*/
@VisibleForTesting
@@ -418,10 +436,10 @@
ApplicationExitInfo info = getExitInfoLocked(
raw.getPackageName(), raw.getPackageUid(), raw.getPid());
- if (info == null) {
+ if (info == null || preventExitInfoUpdate(info)) {
info = addExitInfoLocked(raw);
} else {
- // always override the existing info since we are now more informational.
+ // Override the existing info since we have more information.
info.setReason(raw.getReason());
info.setSubReason(raw.getSubReason());
info.setStatus(0);
@@ -431,24 +449,8 @@
scheduleLogToStatsdLocked(info, true);
}
- /**
- * Make note when ActivityManagerService gets a recoverable native crash, as the process isn't
- * being killed but the crash should still be added to AppExitInfo. Also, because we're not
- * crashing, don't log out to statsd.
- */
- @VisibleForTesting
- @GuardedBy("mLock")
- void handleNoteAppRecoverableCrashLocked(final ApplicationExitInfo raw) {
- addExitInfoLocked(raw, /* recoverable */ true);
- }
-
@GuardedBy("mLock")
private ApplicationExitInfo addExitInfoLocked(ApplicationExitInfo raw) {
- return addExitInfoLocked(raw, /* recoverable */ false);
- }
-
- @GuardedBy("mLock")
- private ApplicationExitInfo addExitInfoLocked(ApplicationExitInfo raw, boolean recoverable) {
if (!mAppExitInfoLoaded.get()) {
Slog.w(TAG, "Skipping saving the exit info due to ongoing loading from storage");
return null;
@@ -464,13 +466,13 @@
}
}
for (int i = 0; i < packages.length; i++) {
- addExitInfoInnerLocked(packages[i], uid, info, recoverable);
+ addExitInfoInnerLocked(packages[i], uid, info);
}
// SDK sandbox exits are stored under both real and package UID
if (Process.isSdkSandboxUid(uid)) {
for (int i = 0; i < packages.length; i++) {
- addExitInfoInnerLocked(packages[i], raw.getPackageUid(), info, recoverable);
+ addExitInfoInnerLocked(packages[i], raw.getPackageUid(), info);
}
}
@@ -526,72 +528,77 @@
if (k != null) {
uid = k;
}
- ArrayList<ApplicationExitInfo> tlist = mTmpInfoList;
- tlist.clear();
final int targetUid = uid;
+ // Launder the modification bit through a `final` array, as Java doesn't allow you to mutate
+ // a captured boolean inside of a lambda.
+ final boolean[] isModified = {false};
forEachPackageLocked((packageName, records) -> {
AppExitInfoContainer container = records.get(targetUid);
if (container == null) {
return FOREACH_ACTION_NONE;
}
- tlist.clear();
- container.getExitInfoLocked(pid, 1, tlist);
- if (tlist.size() == 0) {
+ mTmpInfoList.clear();
+ container.getExitInfosLocked(pid, /* maxNum */ 0, mTmpInfoList);
+ if (mTmpInfoList.size() == 0) {
return FOREACH_ACTION_NONE;
}
- ApplicationExitInfo info = tlist.get(0);
- if (info.getRealUid() != targetUid) {
- tlist.clear();
- return FOREACH_ACTION_NONE;
- }
- // Okay found it, update its reason.
- updateExistingExitInfoRecordLocked(info, status, reason);
- return FOREACH_ACTION_STOP_ITERATION;
+ for (int i = 0, size = mTmpInfoList.size(); i < size; i++) {
+ ApplicationExitInfo info = mTmpInfoList.get(i);
+ if (info.getRealUid() != targetUid) {
+ continue;
+ }
+ // We only update the most recent `ApplicationExitInfo` for this pid, which will
+ // always be the first one we se as `getExitInfosLocked()` returns them sorted
+ // by most-recent-first.
+ isModified[0] = true;
+ updateExistingExitInfoRecordLocked(info, status, reason);
+ return FOREACH_ACTION_STOP_ITERATION;
+ }
+ return FOREACH_ACTION_NONE;
});
- return tlist.size() > 0;
+ mTmpInfoList.clear();
+ return isModified[0];
}
/**
* Get the exit info with matching package name, filterUid and filterPid (if > 0)
*/
@VisibleForTesting
- void getExitInfo(final String packageName, final int filterUid,
- final int filterPid, final int maxNum, final ArrayList<ApplicationExitInfo> results) {
+ void getExitInfo(final String packageName, final int filterUid, final int filterPid,
+ final int maxNum, final List<ApplicationExitInfo> results) {
final long identity = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
- boolean emptyPackageName = TextUtils.isEmpty(packageName);
- if (!emptyPackageName) {
- // fast path
+ if (!TextUtils.isEmpty(packageName)) {
+ // Fast path - just a single package.
AppExitInfoContainer container = mData.get(packageName, filterUid);
if (container != null) {
- container.getExitInfoLocked(filterPid, maxNum, results);
+ container.getExitInfosLocked(filterPid, maxNum, results);
}
- } else {
- // slow path
- final ArrayList<ApplicationExitInfo> list = mTmpInfoList2;
- list.clear();
- // get all packages
- forEachPackageLocked((name, records) -> {
- AppExitInfoContainer container = records.get(filterUid);
- if (container != null) {
- mTmpInfoList.clear();
- list.addAll(container.toListLocked(mTmpInfoList, filterPid));
- }
- return AppExitInfoTracker.FOREACH_ACTION_NONE;
- });
+ return;
+ }
- Collections.sort(list,
- (a, b) -> Long.compare(b.getTimestamp(), a.getTimestamp()));
- int size = list.size();
- if (maxNum > 0) {
- size = Math.min(size, maxNum);
+ // Slow path - get all the packages.
+ forEachPackageLocked((name, records) -> {
+ AppExitInfoContainer container = records.get(filterUid);
+ if (container != null) {
+ container.getExitInfosLocked(filterPid, /* maxNum */ 0, results);
}
- for (int i = 0; i < size; i++) {
- results.add(list.get(i));
- }
- list.clear();
+ return AppExitInfoTracker.FOREACH_ACTION_NONE;
+ });
+
+ // And while the results for each package are sorted, we should
+ // sort over and trim the quantity of global results as well.
+ Collections.sort(
+ results, (a, b) -> Long.compare(b.getTimestamp(), a.getTimestamp()));
+ if (maxNum <= 0) {
+ return;
+ }
+
+ int elementsToRemove = results.size() - maxNum;
+ for (int i = 0; i < elementsToRemove; i++) {
+ results.removeLast();
}
}
} finally {
@@ -606,12 +613,10 @@
@GuardedBy("mLock")
private ApplicationExitInfo getExitInfoLocked(final String packageName,
final int filterUid, final int filterPid) {
- ArrayList<ApplicationExitInfo> list = mTmpInfoList;
- list.clear();
- getExitInfo(packageName, filterUid, filterPid, 1, list);
-
- ApplicationExitInfo info = list.size() > 0 ? list.get(0) : null;
- list.clear();
+ mTmpInfoList.clear();
+ getExitInfo(packageName, filterUid, filterPid, 1, mTmpInfoList);
+ ApplicationExitInfo info = mTmpInfoList.size() > 0 ? mTmpInfoList.getFirst() : null;
+ mTmpInfoList.clear();
return info;
}
@@ -878,8 +883,7 @@
}
@GuardedBy("mLock")
- private void addExitInfoInnerLocked(String packageName, int uid, ApplicationExitInfo info,
- boolean recoverable) {
+ private void addExitInfoInnerLocked(String packageName, int uid, ApplicationExitInfo info) {
AppExitInfoContainer container = mData.get(packageName, uid);
if (container == null) {
container = new AppExitInfoContainer(mAppExitInfoHistoryListSize);
@@ -893,11 +897,7 @@
}
mData.put(packageName, uid, container);
}
- if (recoverable) {
- container.addRecoverableCrashLocked(info);
- } else {
- container.addExitInfoLocked(info);
- }
+ container.addExitInfoLocked(info);
}
@GuardedBy("mLock")
@@ -1205,7 +1205,7 @@
forEachPackageLocked((name, records) -> {
for (int i = records.size() - 1; i >= 0; i--) {
final AppExitInfoContainer container = records.valueAt(i);
- container.forEachRecordLocked((pid, info) -> {
+ container.forEachRecordLocked((info) -> {
final File traceFile = info.getTraceFile();
if (traceFile != null) {
allFiles.remove(traceFile.getName());
@@ -1322,90 +1322,72 @@
* A container class of {@link android.app.ApplicationExitInfo}
*/
final class AppExitInfoContainer {
- private SparseArray<ApplicationExitInfo> mInfos; // index is a pid
- private SparseArray<ApplicationExitInfo> mRecoverableCrashes; // index is a pid
+ private ArrayList<ApplicationExitInfo> mExitInfos;
private int mMaxCapacity;
private int mUid; // Application uid, not isolated uid.
AppExitInfoContainer(final int maxCapacity) {
- mInfos = new SparseArray<ApplicationExitInfo>();
- mRecoverableCrashes = new SparseArray<ApplicationExitInfo>();
+ mExitInfos = new ArrayList<ApplicationExitInfo>();
mMaxCapacity = maxCapacity;
}
+ @VisibleForTesting
@GuardedBy("mLock")
- void getInfosLocked(SparseArray<ApplicationExitInfo> map, final int filterPid,
- final int maxNum, ArrayList<ApplicationExitInfo> results) {
- if (filterPid > 0) {
- ApplicationExitInfo r = map.get(filterPid);
- if (r != null) {
- results.add(r);
+ void getExitInfosLocked(
+ final int filterPid, final int maxNum, List<ApplicationExitInfo> results) {
+ if (mExitInfos.size() == 0) {
+ return;
+ }
+
+ // Most of the callers might only be interested with the most recent
+ // ApplicationExitInfo, and so we can special case an O(n) walk.
+ if (maxNum == 1) {
+ ApplicationExitInfo result = null;
+ for (int i = 0, size = mExitInfos.size(); i < size; i++) {
+ ApplicationExitInfo info = mExitInfos.get(i);
+ if (filterPid > 0 && info.getPid() != filterPid) {
+ continue;
+ }
+
+ if (result == null || result.getTimestamp() < info.getTimestamp()) {
+ result = info;
+ }
}
+ if (result != null) {
+ results.add(result);
+ }
+ return;
+ }
+
+ mTmpInfoList2.clear();
+ if (filterPid <= 0) {
+ mTmpInfoList2.addAll(mExitInfos);
} else {
- final int numRep = map.size();
- if (maxNum <= 0 || numRep <= maxNum) {
- // Return all records.
- for (int i = 0; i < numRep; i++) {
- results.add(map.valueAt(i));
- }
- Collections.sort(results,
- (a, b) -> Long.compare(b.getTimestamp(), a.getTimestamp()));
- } else {
- if (maxNum == 1) {
- // Most of the caller might be only interested with the most recent one
- ApplicationExitInfo r = map.valueAt(0);
- for (int i = 1; i < numRep; i++) {
- ApplicationExitInfo t = map.valueAt(i);
- if (r.getTimestamp() < t.getTimestamp()) {
- r = t;
- }
- }
- results.add(r);
- } else {
- // Huh, need to sort it out then.
- ArrayList<ApplicationExitInfo> list = mTmpInfoList2;
- list.clear();
- for (int i = 0; i < numRep; i++) {
- list.add(map.valueAt(i));
- }
- Collections.sort(list,
- (a, b) -> Long.compare(b.getTimestamp(), a.getTimestamp()));
- for (int i = 0; i < maxNum; i++) {
- results.add(list.get(i));
- }
- list.clear();
+ for (int i = 0, size = mExitInfos.size(); i < size; i++) {
+ ApplicationExitInfo info = mExitInfos.get(i);
+ if (info.getPid() == filterPid) {
+ mTmpInfoList2.add(info);
}
}
}
- }
- @GuardedBy("mLock")
- void getExitInfoLocked(final int filterPid, final int maxNum,
- ArrayList<ApplicationExitInfo> results) {
- getInfosLocked(mInfos, filterPid, maxNum, results);
- }
-
- @GuardedBy("mLock")
- void addInfoLocked(SparseArray<ApplicationExitInfo> map, ApplicationExitInfo info) {
- int size;
- if ((size = map.size()) >= mMaxCapacity) {
- int oldestIndex = -1;
- long oldestTimeStamp = Long.MAX_VALUE;
- for (int i = 0; i < size; i++) {
- ApplicationExitInfo r = map.valueAt(i);
- if (r.getTimestamp() < oldestTimeStamp) {
- oldestTimeStamp = r.getTimestamp();
- oldestIndex = i;
- }
- }
- if (oldestIndex >= 0) {
- final File traceFile = map.valueAt(oldestIndex).getTraceFile();
- if (traceFile != null) {
- traceFile.delete();
- }
- map.removeAt(oldestIndex);
- }
+ Collections.sort(
+ mTmpInfoList2, (a, b) -> Long.compare(b.getTimestamp(), a.getTimestamp()));
+ if (maxNum <= 0) {
+ results.addAll(mTmpInfoList2);
+ return;
}
+
+ int elementsToRemove = mTmpInfoList2.size() - maxNum;
+ for (int i = 0; i < elementsToRemove; i++) {
+ mTmpInfoList2.removeLast();
+ }
+ results.addAll(mTmpInfoList2);
+ }
+
+ @VisibleForTesting
+ @GuardedBy("mLock")
+ void addExitInfoLocked(ApplicationExitInfo info) {
// Claim the state information if there is any
int uid = info.getPackageUid();
// SDK sandbox app states and app traces are stored under real UID
@@ -1420,24 +1402,39 @@
if (info.getTraceFile() == null) {
info.setTraceFile(findAndRemoveFromSparse2dArray(mActiveAppTraces, uid, pid));
}
-
info.setAppTraceRetriever(mAppTraceRetriever);
- map.append(pid, info);
+
+ mExitInfos.add(info);
+ if (mExitInfos.size() <= mMaxCapacity) {
+ return;
+ }
+
+ ApplicationExitInfo oldest = null;
+ for (int i = 0, size = mExitInfos.size(); i < size; i++) {
+ ApplicationExitInfo info2 = mExitInfos.get(i);
+ if (oldest == null || info2.getTimestamp() < oldest.getTimestamp()) {
+ oldest = info2;
+ }
+ }
+ File traceFile = oldest.getTraceFile();
+ if (traceFile != null) {
+ traceFile.delete();
+ }
+ mExitInfos.remove(oldest);
}
@GuardedBy("mLock")
- void addExitInfoLocked(ApplicationExitInfo info) {
- addInfoLocked(mInfos, info);
- }
-
- @GuardedBy("mLock")
- void addRecoverableCrashLocked(ApplicationExitInfo info) {
- addInfoLocked(mRecoverableCrashes, info);
+ ApplicationExitInfo getLastExitInfoForPid(final int pid) {
+ mTmpInfoList.clear();
+ getExitInfosLocked(pid, /* maxNum */ 1, mTmpInfoList);
+ ApplicationExitInfo info = mTmpInfoList.size() == 0 ? null : mTmpInfoList.getFirst();
+ mTmpInfoList.clear();
+ return info;
}
@GuardedBy("mLock")
boolean appendTraceIfNecessaryLocked(final int pid, final File traceFile) {
- final ApplicationExitInfo r = mInfos.get(pid);
+ final ApplicationExitInfo r = getLastExitInfoForPid(pid);
if (r != null) {
r.setTraceFile(traceFile);
r.setAppTraceRetriever(mAppTraceRetriever);
@@ -1447,49 +1444,36 @@
}
@GuardedBy("mLock")
- void destroyLocked(SparseArray<ApplicationExitInfo> map) {
- for (int i = map.size() - 1; i >= 0; i--) {
- ApplicationExitInfo ai = map.valueAt(i);
- final File traceFile = ai.getTraceFile();
+ void destroyLocked() {
+ for (int i = 0, size = mExitInfos.size(); i < size; i++) {
+ ApplicationExitInfo info = mExitInfos.get(i);
+ final File traceFile = info.getTraceFile();
if (traceFile != null) {
traceFile.delete();
}
- ai.setTraceFile(null);
- ai.setAppTraceRetriever(null);
+ info.setTraceFile(null);
+ info.setAppTraceRetriever(null);
}
}
+ /**
+ * Go through each record in an *unspecified* order, execute `callback()` on each element,
+ * and potentially do some action (stopping iteration, removing the element, etc.) based on
+ * the return value of the callback.
+ */
@GuardedBy("mLock")
- void destroyLocked() {
- destroyLocked(mInfos);
- destroyLocked(mRecoverableCrashes);
- }
-
- @GuardedBy("mLock")
- void forEachRecordLocked(final BiFunction<Integer, ApplicationExitInfo, Integer> callback) {
+ void forEachRecordLocked(final Function<ApplicationExitInfo, Integer> callback) {
if (callback == null) return;
- for (int i = mInfos.size() - 1; i >= 0; i--) {
- switch (callback.apply(mInfos.keyAt(i), mInfos.valueAt(i))) {
+ for (int i = mExitInfos.size() - 1; i >= 0; i--) {
+ ApplicationExitInfo info = mExitInfos.get(i);
+ switch (callback.apply(info)) {
case FOREACH_ACTION_STOP_ITERATION: return;
case FOREACH_ACTION_REMOVE_ITEM:
- final File traceFile = mInfos.valueAt(i).getTraceFile();
- if (traceFile != null) {
+ File traceFile;
+ if ((traceFile = info.getTraceFile()) != null) {
traceFile.delete();
}
- mInfos.removeAt(i);
- break;
- }
- }
- for (int i = mRecoverableCrashes.size() - 1; i >= 0; i--) {
- switch (callback.apply(
- mRecoverableCrashes.keyAt(i), mRecoverableCrashes.valueAt(i))) {
- case FOREACH_ACTION_STOP_ITERATION: return;
- case FOREACH_ACTION_REMOVE_ITEM:
- final File traceFile = mRecoverableCrashes.valueAt(i).getTraceFile();
- if (traceFile != null) {
- traceFile.delete();
- }
- mRecoverableCrashes.removeAt(i);
+ mExitInfos.remove(info);
break;
}
}
@@ -1497,30 +1481,20 @@
@GuardedBy("mLock")
void dumpLocked(PrintWriter pw, String prefix, SimpleDateFormat sdf) {
- ArrayList<ApplicationExitInfo> list = new ArrayList<ApplicationExitInfo>();
- for (int i = mInfos.size() - 1; i >= 0; i--) {
- list.add(mInfos.valueAt(i));
+ mTmpInfoList.clear();
+ getExitInfosLocked(/* filterPid */ 0, /* maxNum */ 0, mTmpInfoList);
+ for (int i = 0, size = mTmpInfoList.size(); i < size; i++) {
+ mTmpInfoList.get(i).dump(pw, prefix + " ", "#" + i, sdf);
}
- for (int i = mRecoverableCrashes.size() - 1; i >= 0; i--) {
- list.add(mRecoverableCrashes.valueAt(i));
- }
- Collections.sort(list, (a, b) -> Long.compare(b.getTimestamp(), a.getTimestamp()));
- int size = list.size();
- for (int i = 0; i < size; i++) {
- list.get(i).dump(pw, prefix + " ", "#" + i, sdf);
- }
+ mTmpInfoList.clear();
}
@GuardedBy("mLock")
void writeToProto(ProtoOutputStream proto, long fieldId) {
long token = proto.start(fieldId);
proto.write(AppsExitInfoProto.Package.User.UID, mUid);
- for (int i = 0; i < mInfos.size(); i++) {
- mInfos.valueAt(i).writeToProto(proto, AppsExitInfoProto.Package.User.APP_EXIT_INFO);
- }
- for (int i = 0; i < mRecoverableCrashes.size(); i++) {
- mRecoverableCrashes.valueAt(i).writeToProto(
- proto, AppsExitInfoProto.Package.User.APP_RECOVERABLE_CRASH);
+ for (int i = 0, size = mExitInfos.size(); i < size; i++) {
+ mExitInfos.get(i).writeToProto(proto, AppsExitInfoProto.Package.User.APP_EXIT_INFO);
}
proto.end(token);
}
@@ -1539,14 +1513,7 @@
case (int) AppsExitInfoProto.Package.User.APP_EXIT_INFO: {
ApplicationExitInfo info = new ApplicationExitInfo();
info.readFromProto(proto, AppsExitInfoProto.Package.User.APP_EXIT_INFO);
- mInfos.put(info.getPid(), info);
- break;
- }
- case (int) AppsExitInfoProto.Package.User.APP_RECOVERABLE_CRASH: {
- ApplicationExitInfo info = new ApplicationExitInfo();
- info.readFromProto(
- proto, AppsExitInfoProto.Package.User.APP_RECOVERABLE_CRASH);
- mRecoverableCrashes.put(info.getPid(), info);
+ mExitInfos.add(info);
break;
}
}
@@ -1554,24 +1521,6 @@
proto.end(token);
return mUid;
}
-
- @GuardedBy("mLock")
- List<ApplicationExitInfo> toListLocked(List<ApplicationExitInfo> list, int filterPid) {
- if (list == null) {
- list = new ArrayList<ApplicationExitInfo>();
- }
- for (int i = mInfos.size() - 1; i >= 0; i--) {
- if (filterPid == 0 || filterPid == mInfos.keyAt(i)) {
- list.add(mInfos.valueAt(i));
- }
- }
- for (int i = mRecoverableCrashes.size() - 1; i >= 0; i--) {
- if (filterPid == 0 || filterPid == mRecoverableCrashes.keyAt(i)) {
- list.add(mRecoverableCrashes.valueAt(i));
- }
- }
- return list;
- }
}
/**
@@ -1750,7 +1699,11 @@
case MSG_APP_RECOVERABLE_CRASH: {
ApplicationExitInfo raw = (ApplicationExitInfo) msg.obj;
synchronized (mLock) {
- handleNoteAppRecoverableCrashLocked(raw);
+ // Unlike MSG_APP_KILL, this is a recoverable crash, and
+ // so we want to bypass the statsd app-kill logging.
+ // Hence, call `addExitInfoLocked()` directly instead of
+ // `handleNoteAppKillLocked()`.
+ addExitInfoLocked(raw);
}
recycleRawRecord(raw);
}
diff --git a/services/core/java/com/android/server/am/AppStartInfoTracker.java b/services/core/java/com/android/server/am/AppStartInfoTracker.java
index 4a7ad31..3042b2a 100644
--- a/services/core/java/com/android/server/am/AppStartInfoTracker.java
+++ b/services/core/java/com/android/server/am/AppStartInfoTracker.java
@@ -1195,8 +1195,21 @@
// Records are sorted newest to oldest, grab record at index 0.
ApplicationStartInfo startInfo = mInfos.get(0);
+ int startupState = startInfo.getStartupState();
- if (!isAddTimestampAllowed(startInfo, key, timestampNs)) {
+ // If startup state is error then don't accept any further timestamps.
+ if (startupState == ApplicationStartInfo.STARTUP_STATE_ERROR) {
+ if (DEBUG) Slog.d(TAG, "Startup state is error, not accepting new timestamps.");
+ return;
+ }
+
+ // If startup state is first frame drawn then only accept fully drawn timestamp.
+ if (startupState == ApplicationStartInfo.STARTUP_STATE_FIRST_FRAME_DRAWN
+ && key != ApplicationStartInfo.START_TIMESTAMP_FULLY_DRAWN) {
+ if (DEBUG) {
+ Slog.d(TAG, "Startup state is first frame drawn and timestamp is not fully "
+ + "drawn, not accepting new timestamps.");
+ }
return;
}
@@ -1209,55 +1222,6 @@
}
}
- private boolean isAddTimestampAllowed(ApplicationStartInfo startInfo, int key,
- long timestampNs) {
- int startupState = startInfo.getStartupState();
-
- // If startup state is error then don't accept any further timestamps.
- if (startupState == ApplicationStartInfo.STARTUP_STATE_ERROR) {
- if (DEBUG) Slog.d(TAG, "Startup state is error, not accepting new timestamps.");
- return false;
- }
-
- Map<Integer, Long> timestamps = startInfo.getStartupTimestamps();
-
- if (startupState == ApplicationStartInfo.STARTUP_STATE_FIRST_FRAME_DRAWN) {
- switch (key) {
- case ApplicationStartInfo.START_TIMESTAMP_FULLY_DRAWN:
- // Allowed, continue to confirm it's not already added.
- break;
- case ApplicationStartInfo.START_TIMESTAMP_INITIAL_RENDERTHREAD_FRAME:
- Long firstFrameTimeNs = timestamps
- .get(ApplicationStartInfo.START_TIMESTAMP_FIRST_FRAME);
- if (firstFrameTimeNs == null) {
- // This should never happen. State can't be first frame drawn if first
- // frame timestamp was not provided.
- return false;
- }
-
- if (timestampNs > firstFrameTimeNs) {
- // Initial renderthread frame has to occur before first frame.
- return false;
- }
-
- // Allowed, continue to confirm it's not already added.
- break;
- case ApplicationStartInfo.START_TIMESTAMP_SURFACEFLINGER_COMPOSITION_COMPLETE:
- // Allowed, continue to confirm it's not already added.
- break;
- default:
- return false;
- }
- }
-
- if (timestamps.get(key) != null) {
- // Timestamp should not occur more than once for a given start.
- return false;
- }
-
- return true;
- }
-
@GuardedBy("mLock")
void dumpLocked(PrintWriter pw, String prefix, SimpleDateFormat sdf) {
if (mMonitoringModeEnabled) {
diff --git a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
index 178171d..aeebae4 100644
--- a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
+++ b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
@@ -2482,7 +2482,8 @@
ipw.println();
if (dumpConstants) {
- mConstants.dump(ipw);
+ mFgConstants.dump(ipw);
+ mBgConstants.dump(ipw);
}
if (dumpHistory) {
diff --git a/services/core/java/com/android/server/am/ContentProviderHelper.java b/services/core/java/com/android/server/am/ContentProviderHelper.java
index a8b9e43..4ff1367 100644
--- a/services/core/java/com/android/server/am/ContentProviderHelper.java
+++ b/services/core/java/com/android/server/am/ContentProviderHelper.java
@@ -674,7 +674,9 @@
if (conn != null) {
conn.waiting = true;
}
- cpr.wait(wait);
+ if (wait > 0) {
+ cpr.wait(wait);
+ }
if (cpr.provider == null) {
timedOut = true;
break;
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index fa0e2ca..30efa3e 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -2335,6 +2335,14 @@
// Never stop system user
return;
}
+ synchronized(mLock) {
+ final UserState uss = mStartedUsers.get(oldUserId);
+ if (uss == null || uss.state == UserState.STATE_STOPPING
+ || uss.state == UserState.STATE_SHUTDOWN) {
+ // We've stopped (or are stopping) the user anyway, so don't bother scheduling.
+ return;
+ }
+ }
if (oldUserId == mInjector.getUserManagerInternal().getMainUserId()) {
// MainUser is currently special for things like Docking, so we'll exempt it for now.
Slogf.i(TAG, "Exempting user %d from being stopped due to inactivity by virtue "
@@ -2371,6 +2379,12 @@
// We'll soon want to switch to this user, so don't kill it now.
return;
}
+ final UserInfo currentOrTargetUser = getCurrentUserLU();
+ if (currentOrTargetUser != null && currentOrTargetUser.isGuest()) {
+ // Don't kill any background users for the sake of a Guest. Just reschedule instead.
+ scheduleStopOfBackgroundUser(userId);
+ return;
+ }
Slogf.i(TAG, "Stopping background user %d due to inactivity", userId);
stopUsersLU(userId, /* allowDelayedLocking= */ true, null, null);
}
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 1bb7922..f61bd60 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -2790,8 +2790,9 @@
* have information on them.
*/
private static boolean isOpAllowedForUid(int uid) {
+ int appId = UserHandle.getAppId(uid);
return Flags.runtimePermissionAppopsMappingEnabled()
- && (uid == Process.ROOT_UID || uid == Process.SYSTEM_UID);
+ && (appId == Process.ROOT_UID || appId == Process.SYSTEM_UID);
}
@Override
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 684cb24..6d1983e 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -783,9 +783,11 @@
AudioSystem.DEVICE_OUT_HDMI_EARC
));
+ private final Object mAbsoluteVolumeDeviceInfoMapLock = new Object();
// Devices where the framework sends a full scale audio signal, and controls the volume of
// the external audio system separately.
// For possible volume behaviors, see {@link AudioManager.AbsoluteDeviceVolumeBehavior}.
+ @GuardedBy("mAbsoluteVolumeDeviceInfoMapLock")
Map<Integer, AbsoluteVolumeDeviceInfo> mAbsoluteVolumeDeviceInfoMap = new ArrayMap<>();
/**
@@ -3715,9 +3717,8 @@
int oldIndex = mStreamStates[streamType].getIndex(device);
// Check if the volume adjustment should be handled by an absolute volume controller instead
- if (isAbsoluteVolumeDevice(device)
- && (flags & AudioManager.FLAG_ABSOLUTE_VOLUME) == 0) {
- AbsoluteVolumeDeviceInfo info = mAbsoluteVolumeDeviceInfoMap.get(device);
+ if (isAbsoluteVolumeDevice(device) && (flags & AudioManager.FLAG_ABSOLUTE_VOLUME) == 0) {
+ final AbsoluteVolumeDeviceInfo info = getAbsoluteVolumeDeviceInfo(device);
if (info.mHandlesVolumeAdjustment) {
dispatchAbsoluteVolumeAdjusted(streamType, info, oldIndex, direction,
keyEventMode);
@@ -3784,7 +3785,7 @@
mDeviceBroker.postSetAvrcpAbsoluteVolumeIndex(newIndex / 10);
} else if (isAbsoluteVolumeDevice(device)
&& (flags & AudioManager.FLAG_ABSOLUTE_VOLUME) == 0) {
- AbsoluteVolumeDeviceInfo info = mAbsoluteVolumeDeviceInfoMap.get(device);
+ final AbsoluteVolumeDeviceInfo info = getAbsoluteVolumeDeviceInfo(device);
dispatchAbsoluteVolumeChanged(streamType, info, newIndex);
}
@@ -4787,7 +4788,7 @@
mDeviceBroker.postSetAvrcpAbsoluteVolumeIndex(index / 10);
} else if (isAbsoluteVolumeDevice(device)
&& ((flags & AudioManager.FLAG_ABSOLUTE_VOLUME) == 0)) {
- AbsoluteVolumeDeviceInfo info = mAbsoluteVolumeDeviceInfoMap.get(device);
+ final AbsoluteVolumeDeviceInfo info = getAbsoluteVolumeDeviceInfo(device);
dispatchAbsoluteVolumeChanged(streamType, info, index);
}
@@ -7575,7 +7576,8 @@
if (register) {
AbsoluteVolumeDeviceInfo info = new AbsoluteVolumeDeviceInfo(
device, volumes, cb, handlesVolumeAdjustment, deviceVolumeBehavior);
- AbsoluteVolumeDeviceInfo oldInfo = mAbsoluteVolumeDeviceInfoMap.get(deviceOut);
+ final AbsoluteVolumeDeviceInfo oldInfo = getAbsoluteVolumeDeviceInfo(deviceOut);
+
boolean volumeBehaviorChanged = (oldInfo == null)
|| (oldInfo.mDeviceVolumeBehavior != deviceVolumeBehavior);
if (volumeBehaviorChanged) {
@@ -7735,8 +7737,10 @@
if (mAbsVolumeMultiModeCaseDevices.contains(audioSystemDeviceOut)) {
return AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE;
}
- if (mAbsoluteVolumeDeviceInfoMap.containsKey(audioSystemDeviceOut)) {
- return mAbsoluteVolumeDeviceInfoMap.get(audioSystemDeviceOut).mDeviceVolumeBehavior;
+ synchronized (mAbsoluteVolumeDeviceInfoMapLock) {
+ if (mAbsoluteVolumeDeviceInfoMap.containsKey(audioSystemDeviceOut)) {
+ return mAbsoluteVolumeDeviceInfoMap.get(audioSystemDeviceOut).mDeviceVolumeBehavior;
+ }
}
if (isA2dpAbsoluteVolumeDevice(audioSystemDeviceOut)
@@ -11774,10 +11778,12 @@
}
private Set<Integer> getAbsoluteVolumeDevicesWithBehavior(int behavior) {
- return mAbsoluteVolumeDeviceInfoMap.entrySet().stream()
- .filter(entry -> entry.getValue().mDeviceVolumeBehavior == behavior)
- .map(Map.Entry::getKey)
- .collect(Collectors.toSet());
+ synchronized (mAbsoluteVolumeDeviceInfoMapLock) {
+ return mAbsoluteVolumeDeviceInfoMap.entrySet().stream()
+ .filter(entry -> entry.getValue().mDeviceVolumeBehavior == behavior)
+ .map(Map.Entry::getKey)
+ .collect(Collectors.toSet());
+ }
}
private String dumpDeviceTypes(@NonNull Set<Integer> deviceTypes) {
@@ -14270,14 +14276,26 @@
}
/**
+ * Returns the input device which uses absolute volume behavior, including its variants,
+ * or {@code null} if there is no mapping for the device type
+ */
+ @Nullable
+ private AbsoluteVolumeDeviceInfo getAbsoluteVolumeDeviceInfo(int deviceType) {
+ synchronized (mAbsoluteVolumeDeviceInfoMapLock) {
+ return mAbsoluteVolumeDeviceInfoMap.get(deviceType);
+ }
+ }
+
+ /**
* Returns whether the input device uses absolute volume behavior, including its variants.
* For included volume behaviors, see {@link AudioManager.AbsoluteDeviceVolumeBehavior}.
- *
- * This is distinct from Bluetooth A2DP absolute volume behavior
+ * <p>This is distinct from Bluetooth A2DP absolute volume behavior
* ({@link #isA2dpAbsoluteVolumeDevice}).
*/
private boolean isAbsoluteVolumeDevice(int deviceType) {
- return mAbsoluteVolumeDeviceInfoMap.containsKey(deviceType);
+ synchronized (mAbsoluteVolumeDeviceInfoMapLock) {
+ return mAbsoluteVolumeDeviceInfoMap.containsKey(deviceType);
+ }
}
/**
@@ -14389,7 +14407,9 @@
+ AudioDeviceVolumeManager.volumeBehaviorName(info.mDeviceVolumeBehavior)
);
}
- mAbsoluteVolumeDeviceInfoMap.put(audioSystemDeviceOut, info);
+ synchronized (mAbsoluteVolumeDeviceInfoMapLock) {
+ mAbsoluteVolumeDeviceInfoMap.put(audioSystemDeviceOut, info);
+ }
}
private AbsoluteVolumeDeviceInfo removeAudioSystemDeviceOutFromAbsVolumeDevices(
@@ -14398,7 +14418,10 @@
Log.d(TAG, "Removing DeviceType: 0x" + Integer.toHexString(audioSystemDeviceOut)
+ " from mAbsoluteVolumeDeviceInfoMap");
}
- return mAbsoluteVolumeDeviceInfoMap.remove(audioSystemDeviceOut);
+
+ synchronized (mAbsoluteVolumeDeviceInfoMapLock) {
+ return mAbsoluteVolumeDeviceInfoMap.remove(audioSystemDeviceOut);
+ }
}
//====================
diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java
index 0e81eb9..8e8a037 100644
--- a/services/core/java/com/android/server/biometrics/BiometricService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricService.java
@@ -31,8 +31,8 @@
import android.app.UserSwitchObserver;
import android.app.admin.DevicePolicyManager;
import android.app.trust.ITrustManager;
-import android.content.ContentResolver;
import android.content.ComponentName;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
@@ -233,6 +233,7 @@
private static final boolean DEFAULT_KEYGUARD_ENABLED = true;
private static final boolean DEFAULT_APP_ENABLED = true;
private static final boolean DEFAULT_ALWAYS_REQUIRE_CONFIRMATION = false;
+ private static final boolean DEFAULT_MANDATORY_BIOMETRICS_STATUS = false;
// Some devices that shipped before S already have face-specific settings. Instead of
// migrating, which is complicated, let's just keep using the existing settings.
@@ -253,6 +254,8 @@
Settings.Secure.getUriFor(Settings.Secure.BIOMETRIC_KEYGUARD_ENABLED);
private final Uri BIOMETRIC_APP_ENABLED =
Settings.Secure.getUriFor(Settings.Secure.BIOMETRIC_APP_ENABLED);
+ private final Uri MANDATORY_BIOMETRICS_ENABLED =
+ Settings.Secure.getUriFor(Settings.Secure.MANDATORY_BIOMETRICS);
private final ContentResolver mContentResolver;
private final List<BiometricService.EnabledOnKeyguardCallback> mCallbacks;
@@ -260,6 +263,7 @@
private final Map<Integer, Boolean> mBiometricEnabledOnKeyguard = new HashMap<>();
private final Map<Integer, Boolean> mBiometricEnabledForApps = new HashMap<>();
private final Map<Integer, Boolean> mFaceAlwaysRequireConfirmation = new HashMap<>();
+ private final Map<Integer, Boolean> mMandatoryBiometricsEnabled = new HashMap<>();
/**
* Creates a content observer.
@@ -281,6 +285,9 @@
mUseLegacyFaceOnlySettings =
Build.VERSION.DEVICE_INITIAL_SDK_INT <= Build.VERSION_CODES.Q
&& hasFace && !hasFingerprint;
+ mMandatoryBiometricsEnabled.put(context.getUserId(), Settings.Secure.getIntForUser(
+ mContentResolver, Settings.Secure.MANDATORY_BIOMETRICS,
+ DEFAULT_MANDATORY_BIOMETRICS_STATUS ? 1 : 0, context.getUserId()) != 0);
updateContentObserver();
}
@@ -311,6 +318,10 @@
false /* notifyForDescendants */,
this /* observer */,
UserHandle.USER_ALL);
+ mContentResolver.registerContentObserver(MANDATORY_BIOMETRICS_ENABLED,
+ false /* notifyForDescendants */,
+ this /* observer */,
+ UserHandle.USER_ALL);
}
@Override
@@ -353,6 +364,12 @@
Settings.Secure.BIOMETRIC_APP_ENABLED,
DEFAULT_APP_ENABLED ? 1 : 0 /* default */,
userId) != 0);
+ } else if (MANDATORY_BIOMETRICS_ENABLED.equals(uri)) {
+ mMandatoryBiometricsEnabled.put(userId, Settings.Secure.getIntForUser(
+ mContentResolver,
+ Settings.Secure.MANDATORY_BIOMETRICS,
+ DEFAULT_MANDATORY_BIOMETRICS_STATUS ? 1 : 0 /* default */,
+ userId) != 0);
}
}
@@ -394,6 +411,11 @@
}
}
+ public boolean getMandatoryBiometricsEnabledForUser(int userId) {
+ return mMandatoryBiometricsEnabled.getOrDefault(userId,
+ DEFAULT_MANDATORY_BIOMETRICS_STATUS);
+ }
+
void notifyEnabledOnKeyguardCallbacks(int userId) {
List<EnabledOnKeyguardCallback> callbacks = mCallbacks;
for (int i = 0; i < callbacks.size(); i++) {
diff --git a/services/core/java/com/android/server/biometrics/PreAuthInfo.java b/services/core/java/com/android/server/biometrics/PreAuthInfo.java
index f085647..b9e6563 100644
--- a/services/core/java/com/android/server/biometrics/PreAuthInfo.java
+++ b/services/core/java/com/android/server/biometrics/PreAuthInfo.java
@@ -29,11 +29,13 @@
import android.content.Context;
import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricManager;
+import android.hardware.biometrics.Flags;
import android.hardware.biometrics.PromptInfo;
import android.os.RemoteException;
import android.util.Pair;
import android.util.Slog;
+import com.android.internal.R;
import com.android.server.biometrics.sensors.LockoutTracker;
import java.lang.annotation.Retention;
@@ -59,6 +61,7 @@
static final int BIOMETRIC_LOCKOUT_TIMED = 10;
static final int BIOMETRIC_LOCKOUT_PERMANENT = 11;
static final int BIOMETRIC_SENSOR_PRIVACY_ENABLED = 12;
+ static final int MANDATORY_BIOMETRIC_UNAVAILABLE_ERROR = 13;
private static final String TAG = "BiometricService/PreAuthInfo";
final boolean credentialRequested;
// Sensors that can be used for this request (e.g. strong enough, enrolled, enabled).
@@ -73,12 +76,14 @@
private final boolean mBiometricRequested;
private final int mBiometricStrengthRequested;
private final BiometricCameraManager mBiometricCameraManager;
+ private final boolean mOnlyMandatoryBiometricsRequested;
private PreAuthInfo(boolean biometricRequested, int biometricStrengthRequested,
boolean credentialRequested, List<BiometricSensor> eligibleSensors,
List<Pair<BiometricSensor, Integer>> ineligibleSensors, boolean credentialAvailable,
- boolean confirmationRequested, boolean ignoreEnrollmentState, int userId,
- Context context, BiometricCameraManager biometricCameraManager) {
+ PromptInfo promptInfo, int userId, Context context,
+ BiometricCameraManager biometricCameraManager,
+ boolean isOnlyMandatoryBiometricsRequested) {
mBiometricRequested = biometricRequested;
mBiometricStrengthRequested = biometricStrengthRequested;
mBiometricCameraManager = biometricCameraManager;
@@ -87,10 +92,11 @@
this.eligibleSensors = eligibleSensors;
this.ineligibleSensors = ineligibleSensors;
this.credentialAvailable = credentialAvailable;
- this.confirmationRequested = confirmationRequested;
- this.ignoreEnrollmentState = ignoreEnrollmentState;
+ this.confirmationRequested = promptInfo.isConfirmationRequested();
+ this.ignoreEnrollmentState = promptInfo.isIgnoreEnrollmentState();
this.userId = userId;
this.context = context;
+ this.mOnlyMandatoryBiometricsRequested = isOnlyMandatoryBiometricsRequested;
}
static PreAuthInfo create(ITrustManager trustManager,
@@ -102,7 +108,16 @@
BiometricCameraManager biometricCameraManager)
throws RemoteException {
- final boolean confirmationRequested = promptInfo.isConfirmationRequested();
+ final boolean isOnlyMandatoryBiometricsRequested = promptInfo.getAuthenticators()
+ == BiometricManager.Authenticators.MANDATORY_BIOMETRICS;
+
+ if (dropCredentialFallback(promptInfo.getAuthenticators(),
+ settingObserver.getMandatoryBiometricsEnabledForUser(userId),
+ trustManager)) {
+ promptInfo.setAuthenticators(BiometricManager.Authenticators.BIOMETRIC_STRONG);
+ promptInfo.setNegativeButtonText(context.getString(R.string.cancel));
+ }
+
final boolean biometricRequested = Utils.isBiometricRequested(promptInfo);
final int requestedStrength = Utils.getPublicBiometricStrength(promptInfo);
final boolean credentialRequested = Utils.isCredentialRequested(promptInfo);
@@ -150,8 +165,27 @@
}
return new PreAuthInfo(biometricRequested, requestedStrength, credentialRequested,
- eligibleSensors, ineligibleSensors, credentialAvailable, confirmationRequested,
- promptInfo.isIgnoreEnrollmentState(), userId, context, biometricCameraManager);
+ eligibleSensors, ineligibleSensors, credentialAvailable, promptInfo, userId,
+ context, biometricCameraManager, isOnlyMandatoryBiometricsRequested);
+ }
+
+ private static boolean dropCredentialFallback(int authenticators,
+ boolean isMandatoryBiometricsEnabled, ITrustManager trustManager) {
+ final boolean isMandatoryBiometricsRequested =
+ (authenticators & BiometricManager.Authenticators.MANDATORY_BIOMETRICS)
+ == BiometricManager.Authenticators.MANDATORY_BIOMETRICS;
+ if (Flags.mandatoryBiometrics() && isMandatoryBiometricsEnabled
+ && isMandatoryBiometricsRequested) {
+ try {
+ final boolean isInSignificantPlace = trustManager.isInSignificantPlace();
+ return !isInSignificantPlace;
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception while trying to check "
+ + "if user is in a trusted location.");
+ }
+ }
+
+ return false;
}
/**
@@ -353,6 +387,25 @@
status = CREDENTIAL_NOT_ENROLLED;
}
}
+ } else if (Flags.mandatoryBiometrics() && mOnlyMandatoryBiometricsRequested) {
+ if (!eligibleSensors.isEmpty()) {
+ for (BiometricSensor sensor : eligibleSensors) {
+ modality |= sensor.modality;
+ }
+
+ if (modality == TYPE_FACE && cameraPrivacyEnabled) {
+ // If the only modality requested is face, credential is unavailable,
+ // and the face sensor privacy is enabled then return
+ // BIOMETRIC_SENSOR_PRIVACY_ENABLED.
+ //
+ // Note: This sensor will not be eligible for calls to authenticate.
+ status = BIOMETRIC_SENSOR_PRIVACY_ENABLED;
+ } else {
+ status = AUTHENTICATOR_OK;
+ }
+ } else {
+ status = MANDATORY_BIOMETRIC_UNAVAILABLE_ERROR;
+ }
} else if (mBiometricRequested) {
if (!eligibleSensors.isEmpty()) {
for (BiometricSensor sensor : eligibleSensors) {
@@ -509,7 +562,8 @@
CREDENTIAL_NOT_ENROLLED,
BIOMETRIC_LOCKOUT_TIMED,
BIOMETRIC_LOCKOUT_PERMANENT,
- BIOMETRIC_SENSOR_PRIVACY_ENABLED})
+ BIOMETRIC_SENSOR_PRIVACY_ENABLED,
+ MANDATORY_BIOMETRIC_UNAVAILABLE_ERROR})
@Retention(RetentionPolicy.SOURCE)
@interface AuthenticatorStatus {
}
diff --git a/services/core/java/com/android/server/biometrics/Utils.java b/services/core/java/com/android/server/biometrics/Utils.java
index 4af30a9..df29ca4 100644
--- a/services/core/java/com/android/server/biometrics/Utils.java
+++ b/services/core/java/com/android/server/biometrics/Utils.java
@@ -140,6 +140,14 @@
}
/**
+ * @param authenticators composed of one or more values from {@link Authenticators}
+ * @return true if mandatory biometrics is requested
+ */
+ static boolean isMandatoryBiometricsRequested(@Authenticators.Types int authenticators) {
+ return (authenticators & Authenticators.MANDATORY_BIOMETRICS) != 0;
+ }
+
+ /**
* @param promptInfo should be first processed by
* {@link #combineAuthenticatorBundles(PromptInfo)}
* @return true if device credential is allowed.
@@ -242,7 +250,8 @@
// Check if any of the non-biometric and non-credential bits are set. If so, this is
// invalid.
final int testBits = ~(Authenticators.DEVICE_CREDENTIAL
- | Authenticators.BIOMETRIC_MIN_STRENGTH);
+ | Authenticators.BIOMETRIC_MIN_STRENGTH
+ | Authenticators.MANDATORY_BIOMETRICS);
if ((authenticators & testBits) != 0) {
Slog.e(BiometricService.TAG, "Non-biometric, non-credential bits found."
+ " Authenticators: " + authenticators);
@@ -259,6 +268,8 @@
return true;
} else if (biometricBits == Authenticators.BIOMETRIC_WEAK) {
return true;
+ } else if (isMandatoryBiometricsRequested(authenticators)) {
+ return true;
}
Slog.e(BiometricService.TAG, "Unsupported biometric flags. Authenticators: "
diff --git a/services/core/java/com/android/server/clipboard/ClipboardService.java b/services/core/java/com/android/server/clipboard/ClipboardService.java
index 0afca92..73aa14b 100644
--- a/services/core/java/com/android/server/clipboard/ClipboardService.java
+++ b/services/core/java/com/android/server/clipboard/ClipboardService.java
@@ -251,7 +251,7 @@
}
private void registerVirtualDeviceListener() {
- if (mVirtualDeviceListener != null) {
+ if (mVdm == null || mVirtualDeviceListener != null) {
return;
}
mVirtualDeviceListener = new VirtualDeviceManager.VirtualDeviceListener() {
@@ -891,7 +891,8 @@
Slog.e(TAG, "RemoteException calling UserManager: " + e);
return null;
}
- if (deviceId != DEVICE_ID_DEFAULT && !mVdm.isValidVirtualDeviceId(deviceId)) {
+ if (deviceId != DEVICE_ID_DEFAULT
+ && mVdm != null && !mVdm.isValidVirtualDeviceId(deviceId)) {
Slog.w(TAG, "getClipboardLocked called with invalid (possibly released) deviceId "
+ deviceId);
return null;
@@ -1467,8 +1468,8 @@
return;
}
// Don't notify if this access is coming from the privileged app which owns the device.
- if (clipboard.deviceId != DEVICE_ID_DEFAULT && mVdmInternal.getDeviceOwnerUid(
- clipboard.deviceId) == uid) {
+ if (clipboard.deviceId != DEVICE_ID_DEFAULT && mVdmInternal != null
+ && mVdmInternal.getDeviceOwnerUid(clipboard.deviceId) == uid) {
return;
}
// Don't notify if already notified for this uid and clip.
@@ -1519,7 +1520,7 @@
private ArraySet<Context> getToastContexts(Clipboard clipboard) throws IllegalStateException {
ArraySet<Context> contexts = new ArraySet<>();
- if (clipboard.deviceId != DEVICE_ID_DEFAULT) {
+ if (mVdmInternal != null && clipboard.deviceId != DEVICE_ID_DEFAULT) {
DisplayManager displayManager = getContext().getSystemService(DisplayManager.class);
int topFocusedDisplayId = mWm.getTopFocusedDisplayId();
diff --git a/services/core/java/com/android/server/compat/PlatformCompat.java b/services/core/java/com/android/server/compat/PlatformCompat.java
index f8fd0a0..22b85d4 100644
--- a/services/core/java/com/android/server/compat/PlatformCompat.java
+++ b/services/core/java/com/android/server/compat/PlatformCompat.java
@@ -83,9 +83,10 @@
@VisibleForTesting
PlatformCompat(Context context, CompatConfig compatConfig,
- AndroidBuildClassifier buildClassifier) {
+ AndroidBuildClassifier buildClassifier,
+ ChangeReporter changeReporter) {
mContext = context;
- mChangeReporter = new ChangeReporter(ChangeReporter.SOURCE_SYSTEM_SERVER);
+ mChangeReporter = changeReporter;
mCompatConfig = compatConfig;
mBuildClassifier = buildClassifier;
@@ -96,8 +97,11 @@
@EnforcePermission(LOG_COMPAT_CHANGE)
public void reportChange(long changeId, ApplicationInfo appInfo) {
super.reportChange_enforcePermission();
-
- reportChangeInternal(changeId, appInfo.uid, ChangeReporter.STATE_LOGGED);
+ reportChangeInternal(
+ changeId,
+ appInfo.uid,
+ appInfo.isSystemApp(),
+ ChangeReporter.STATE_LOGGED);
}
@Override
@@ -108,7 +112,11 @@
ApplicationInfo appInfo = getApplicationInfo(packageName, userId);
if (appInfo != null) {
- reportChangeInternal(changeId, appInfo.uid, ChangeReporter.STATE_LOGGED);
+ reportChangeInternal(
+ changeId,
+ appInfo.uid,
+ appInfo.isSystemApp(),
+ ChangeReporter.STATE_LOGGED);
}
}
@@ -117,7 +125,7 @@
public void reportChangeByUid(long changeId, int uid) {
super.reportChangeByUid_enforcePermission();
- reportChangeInternal(changeId, uid, ChangeReporter.STATE_LOGGED);
+ reportChangeInternal(changeId, uid, false, ChangeReporter.STATE_LOGGED);
}
/**
@@ -128,8 +136,8 @@
* @param uid of the user
* @param state of the change - enabled/disabled/logged
*/
- private void reportChangeInternal(long changeId, int uid, int state) {
- mChangeReporter.reportChange(uid, changeId, state, true);
+ private void reportChangeInternal(long changeId, int uid, boolean isKnownSystemApp, int state) {
+ mChangeReporter.reportChange(uid, changeId, state, isKnownSystemApp, true);
}
@Override
@@ -190,7 +198,11 @@
if (appInfo != null) {
boolean isTargetingLatestSdk =
mCompatConfig.isChangeTargetingLatestSdk(c, appInfo.targetSdkVersion);
- mChangeReporter.reportChange(appInfo.uid, changeId, state, isTargetingLatestSdk);
+ mChangeReporter.reportChange(appInfo.uid,
+ changeId,
+ state,
+ appInfo.isSystemApp(),
+ isTargetingLatestSdk);
}
return enabled;
}
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 2d5f38e..e686779 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -1548,16 +1548,20 @@
int flags = virtualDisplayConfig.getFlags();
if (virtualDevice != null) {
final VirtualDeviceManager vdm = mContext.getSystemService(VirtualDeviceManager.class);
- try {
- if (!vdm.isValidVirtualDeviceId(virtualDevice.getDeviceId())) {
- throw new SecurityException("Invalid virtual device");
+ if (vdm != null) {
+ try {
+ if (!vdm.isValidVirtualDeviceId(virtualDevice.getDeviceId())) {
+ throw new SecurityException("Invalid virtual device");
+ }
+ } catch (RemoteException ex) {
+ throw new SecurityException("Unable to validate virtual device");
}
- } catch (RemoteException ex) {
- throw new SecurityException("Unable to validate virtual device");
+ final VirtualDeviceManagerInternal localVdm =
+ getLocalService(VirtualDeviceManagerInternal.class);
+ if (localVdm != null) {
+ flags |= localVdm.getBaseVirtualDisplayFlags(virtualDevice);
+ }
}
- final VirtualDeviceManagerInternal localVdm =
- getLocalService(VirtualDeviceManagerInternal.class);
- flags |= localVdm.getBaseVirtualDisplayFlags(virtualDevice);
}
if (surface != null && surface.isSingleBuffered()) {
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 65a729a..d14f2a0 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -587,7 +587,8 @@
mUniqueDisplayId,
mThermalBrightnessThrottlingDataId,
logicalDisplay.getPowerThrottlingDataIdLocked(),
- mDisplayDeviceConfig), mContext, flags, mSensorManager);
+ mDisplayDeviceConfig,
+ mDisplayId), mContext, flags, mSensorManager);
// Seed the cached brightness
saveBrightnessInfo(getScreenBrightnessSetting());
mAutomaticBrightnessStrategy =
@@ -892,7 +893,8 @@
// will call updatePowerState if needed.
mBrightnessClamperController.onDisplayChanged(
new BrightnessClamperController.DisplayDeviceData(uniqueId,
- thermalBrightnessThrottlingDataId, powerThrottlingDataId, config));
+ thermalBrightnessThrottlingDataId, powerThrottlingDataId,
+ config, mDisplayId));
if (changed) {
updatePowerState();
diff --git a/services/core/java/com/android/server/display/brightness/clamper/BrightnessClamperController.java b/services/core/java/com/android/server/display/brightness/clamper/BrightnessClamperController.java
index 101ad30..2206402 100644
--- a/services/core/java/com/android/server/display/brightness/clamper/BrightnessClamperController.java
+++ b/services/core/java/com/android/server/display/brightness/clamper/BrightnessClamperController.java
@@ -23,23 +23,17 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
-import android.content.res.Resources;
-import android.hardware.Sensor;
-import android.hardware.SensorEvent;
-import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.hardware.display.BrightnessInfo;
import android.hardware.display.DisplayManagerInternal;
import android.os.Handler;
import android.os.HandlerExecutor;
import android.os.PowerManager;
-import android.os.SystemClock;
import android.provider.DeviceConfig;
import android.provider.DeviceConfigInterface;
import android.util.IndentingPrintWriter;
import android.util.Slog;
-import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.display.DisplayBrightnessState;
import com.android.server.display.DisplayDeviceConfig;
@@ -50,30 +44,22 @@
import com.android.server.display.config.SensorData;
import com.android.server.display.feature.DeviceConfigParameterProvider;
import com.android.server.display.feature.DisplayManagerFlags;
-import com.android.server.display.utils.AmbientFilter;
-import com.android.server.display.utils.AmbientFilterFactory;
-import com.android.server.display.utils.DebugUtils;
-import com.android.server.display.utils.SensorUtils;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executor;
-import java.util.concurrent.TimeUnit;
/**
* Clampers controller, all in DisplayControllerHandler
*/
public class BrightnessClamperController {
private static final String TAG = "BrightnessClamperController";
- // To enable these logs, run:
- // 'adb shell setprop persist.log.tag.BrightnessClamperController DEBUG && adb reboot'
- private static final boolean DEBUG = DebugUtils.isDebuggable(TAG);
- public static final float INVALID_LUX = -1f;
private final DeviceConfigParameterProvider mDeviceConfigParameterProvider;
private final Handler mHandler;
- private final SensorManager mSensorManager;
+ private final LightSensorController mLightSensorController;
+
private final ClamperChangeListener mClamperChangeListenerExternal;
private final Executor mExecutor;
private final List<BrightnessClamper<? super DisplayDeviceData>> mClampers;
@@ -85,70 +71,49 @@
private float mCustomAnimationRate = DisplayBrightnessState.CUSTOM_ANIMATION_RATE_NOT_SET;
@Nullable
private Type mClamperType = null;
- private final SensorEventListener mLightSensorListener;
- private Sensor mRegisteredLightSensor = null;
- private Sensor mLightSensor;
- private String mLightSensorType;
- private String mLightSensorName;
- private AmbientFilter mAmbientFilter;
- private final DisplayDeviceConfig mDisplayDeviceConfig;
- private final Resources mResources;
- private final int mLightSensorRate;
- private final Injector mInjector;
private boolean mClamperApplied = false;
+ private final LightSensorController.LightSensorListener mLightSensorListener =
+ new LightSensorController.LightSensorListener() {
+ @Override
+ public void onAmbientLuxChange(float lux) {
+ mModifiers.forEach(mModifier -> mModifier.setAmbientLux(lux));
+ }
+ };
+
public BrightnessClamperController(Handler handler,
ClamperChangeListener clamperChangeListener, DisplayDeviceData data, Context context,
DisplayManagerFlags flags, SensorManager sensorManager) {
- this(null, handler, clamperChangeListener, data, context, flags, sensorManager);
+ this(new Injector(), handler, clamperChangeListener, data, context, flags, sensorManager);
}
@VisibleForTesting
BrightnessClamperController(Injector injector, Handler handler,
ClamperChangeListener clamperChangeListener, DisplayDeviceData data, Context context,
DisplayManagerFlags flags, SensorManager sensorManager) {
- mInjector = injector == null ? new Injector() : injector;
- mDeviceConfigParameterProvider = mInjector.getDeviceConfigParameterProvider();
+ mDeviceConfigParameterProvider = injector.getDeviceConfigParameterProvider();
mHandler = handler;
- mSensorManager = sensorManager;
- mDisplayDeviceConfig = data.mDisplayDeviceConfig;
- mLightSensorListener = new SensorEventListener() {
- @Override
- public void onSensorChanged(SensorEvent event) {
- long now = SystemClock.elapsedRealtime();
- mAmbientFilter.addValue(TimeUnit.NANOSECONDS.toMillis(event.timestamp),
- event.values[0]);
- final float lux = mAmbientFilter.getEstimate(now);
- mModifiers.forEach(mModifier -> mModifier.setAmbientLux(lux));
- }
-
- @Override
- public void onAccuracyChanged(Sensor sensor, int accuracy) {
- // unused
- }
- };
+ mLightSensorController = injector.getLightSensorController(sensorManager, context,
+ mLightSensorListener, mHandler);
mClamperChangeListenerExternal = clamperChangeListener;
mExecutor = new HandlerExecutor(handler);
- mResources = context.getResources();
- mLightSensorRate = context.getResources().getInteger(
- R.integer.config_autoBrightnessLightSensorRate);
Runnable clamperChangeRunnableInternal = this::recalculateBrightnessCap;
-
ClamperChangeListener clamperChangeListenerInternal = () -> {
if (!mHandler.hasCallbacks(clamperChangeRunnableInternal)) {
mHandler.post(clamperChangeRunnableInternal);
}
};
- mClampers = mInjector.getClampers(handler, clamperChangeListenerInternal, data, flags,
+ mClampers = injector.getClampers(handler, clamperChangeListenerInternal, data, flags,
context);
- mModifiers = mInjector.getModifiers(flags, context, handler, clamperChangeListener,
- data.mDisplayDeviceConfig, mSensorManager);
+ mModifiers = injector.getModifiers(flags, context, handler, clamperChangeListener,
+ data.mDisplayDeviceConfig);
mOnPropertiesChangedListener =
properties -> mClampers.forEach(BrightnessClamper::onDeviceConfigChanged);
+ mLightSensorController.configure(data.getAmbientLightSensor(), data.getDisplayId());
start();
}
@@ -156,7 +121,9 @@
* Should be called when display changed. Forwards the call to individual clampers
*/
public void onDisplayChanged(DisplayDeviceData data) {
+ mLightSensorController.configure(data.getAmbientLightSensor(), data.getDisplayId());
mClampers.forEach(clamper -> clamper.onDisplayChanged(data));
+ adjustLightSensorSubscription();
}
/**
@@ -184,9 +151,9 @@
}
if (displayState != STATE_ON) {
- unregisterSensorListener();
+ mLightSensorController.stop();
} else {
- maybeRegisterLightSensor();
+ adjustLightSensorSubscription();
}
for (int i = 0; i < mModifiers.size(); i++) {
@@ -231,9 +198,8 @@
writer.println(" mBrightnessCap: " + mBrightnessCap);
writer.println(" mClamperType: " + mClamperType);
writer.println(" mClamperApplied: " + mClamperApplied);
- writer.println(" mLightSensor=" + mLightSensor);
- writer.println(" mRegisteredLightSensor=" + mRegisteredLightSensor);
IndentingPrintWriter ipw = new IndentingPrintWriter(writer, " ");
+ mLightSensorController.dump(ipw);
mClampers.forEach(clamper -> clamper.dump(ipw));
mModifiers.forEach(modifier -> modifier.dump(ipw));
}
@@ -245,6 +211,7 @@
public void stop() {
mDeviceConfigParameterProvider.removeOnPropertiesChangedListener(
mOnPropertiesChangedListener);
+ mLightSensorController.stop();
mClampers.forEach(BrightnessClamper::stop);
mModifiers.forEach(BrightnessStateModifier::stop);
}
@@ -281,10 +248,15 @@
if (!mClampers.isEmpty()) {
mDeviceConfigParameterProvider.addOnPropertiesChangedListener(
mExecutor, mOnPropertiesChangedListener);
- reloadLightSensorData(mDisplayDeviceConfig);
- mLightSensor = mInjector.getLightSensor(
- mSensorManager, mLightSensorType, mLightSensorName);
- maybeRegisterLightSensor();
+ }
+ adjustLightSensorSubscription();
+ }
+
+ private void adjustLightSensorSubscription() {
+ if (mModifiers.stream().anyMatch(BrightnessStateModifier::shouldListenToLightSensor)) {
+ mLightSensorController.restart();
+ } else {
+ mLightSensorController.stop();
}
}
@@ -323,7 +295,7 @@
List<BrightnessStateModifier> getModifiers(DisplayManagerFlags flags, Context context,
Handler handler, ClamperChangeListener listener,
- DisplayDeviceConfig displayDeviceConfig, SensorManager sensorManager) {
+ DisplayDeviceConfig displayDeviceConfig) {
List<BrightnessStateModifier> modifiers = new ArrayList<>();
modifiers.add(new DisplayDimModifier(context));
modifiers.add(new BrightnessLowPowerModeModifier());
@@ -335,11 +307,12 @@
return modifiers;
}
- Sensor getLightSensor(SensorManager sensorManager, String type, String name) {
- return SensorUtils.findSensor(sensorManager, type,
- name, Sensor.TYPE_LIGHT);
+ LightSensorController getLightSensorController(SensorManager sensorManager,
+ Context context, LightSensorController.LightSensorListener listener,
+ Handler handler) {
+ return new LightSensorController(sensorManager, context.getResources(),
+ listener, handler);
}
-
}
/**
@@ -354,17 +327,21 @@
private final String mThermalThrottlingDataId;
@NonNull
private final String mPowerThrottlingDataId;
-
+ @NonNull
private final DisplayDeviceConfig mDisplayDeviceConfig;
+ private final int mDisplayId;
+
public DisplayDeviceData(@NonNull String uniqueDisplayId,
@NonNull String thermalThrottlingDataId,
@NonNull String powerThrottlingDataId,
- @NonNull DisplayDeviceConfig displayDeviceConfig) {
+ @NonNull DisplayDeviceConfig displayDeviceConfig,
+ int displayId) {
mUniqueDisplayId = uniqueDisplayId;
mThermalThrottlingDataId = thermalThrottlingDataId;
mPowerThrottlingDataId = powerThrottlingDataId;
mDisplayDeviceConfig = displayDeviceConfig;
+ mDisplayId = displayId;
}
@@ -412,55 +389,18 @@
}
@NonNull
+ @Override
public SensorData getTempSensor() {
return mDisplayDeviceConfig.getTempSensor();
}
- }
- private void maybeRegisterLightSensor() {
- if (mModifiers.stream().noneMatch(BrightnessStateModifier::shouldListenToLightSensor)) {
- return;
+ @NonNull
+ SensorData getAmbientLightSensor() {
+ return mDisplayDeviceConfig.getAmbientLightSensor();
}
- if (mRegisteredLightSensor == mLightSensor) {
- return;
- }
-
- if (mRegisteredLightSensor != null) {
- unregisterSensorListener();
- }
-
- mAmbientFilter = AmbientFilterFactory.createBrightnessFilter(TAG, mResources);
- mSensorManager.registerListener(mLightSensorListener,
- mLightSensor, mLightSensorRate * 1000, mHandler);
- mRegisteredLightSensor = mLightSensor;
-
- if (DEBUG) {
- Slog.d(TAG, "maybeRegisterLightSensor");
- }
- }
-
- private void unregisterSensorListener() {
- mSensorManager.unregisterListener(mLightSensorListener);
- mRegisteredLightSensor = null;
- mModifiers.forEach(mModifier -> mModifier.setAmbientLux(INVALID_LUX)); // set lux to invalid
- if (DEBUG) {
- Slog.d(TAG, "unregisterSensorListener");
- }
- }
-
- private void reloadLightSensorData(DisplayDeviceConfig displayDeviceConfig) {
- // The displayDeviceConfig (ddc) contains display specific preferences. When loaded,
- // it naturally falls back to the global config.xml.
- if (displayDeviceConfig != null
- && displayDeviceConfig.getAmbientLightSensor() != null) {
- // This covers both the ddc and the config.xml fallback
- mLightSensorType = displayDeviceConfig.getAmbientLightSensor().type;
- mLightSensorName = displayDeviceConfig.getAmbientLightSensor().name;
- } else if (mLightSensorName == null && mLightSensorType == null) {
- mLightSensorType = mResources.getString(
- com.android.internal.R.string.config_displayLightSensorType);
- mLightSensorName = "";
+ int getDisplayId() {
+ return mDisplayId;
}
}
}
diff --git a/services/core/java/com/android/server/display/brightness/clamper/LightSensorController.java b/services/core/java/com/android/server/display/brightness/clamper/LightSensorController.java
new file mode 100644
index 0000000..d89dd28
--- /dev/null
+++ b/services/core/java/com/android/server/display/brightness/clamper/LightSensorController.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display.brightness.clamper;
+
+import android.annotation.Nullable;
+import android.content.res.Resources;
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.hardware.SensorEventListener;
+import android.hardware.SensorManager;
+import android.os.Handler;
+import android.os.SystemClock;
+import android.util.Slog;
+import android.view.Display;
+
+import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.display.config.SensorData;
+import com.android.server.display.utils.AmbientFilter;
+import com.android.server.display.utils.AmbientFilterFactory;
+import com.android.server.display.utils.DebugUtils;
+import com.android.server.display.utils.SensorUtils;
+
+import java.io.PrintWriter;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Manages light sensor subscription and notifies its listener about ambient lux changes
+ */
+public class LightSensorController {
+ private static final String TAG = "LightSensorController";
+
+ // To enable these logs, run:
+ // 'adb shell setprop persist.log.tag.LightSensorController DEBUG && adb reboot'
+ private static final boolean DEBUG = DebugUtils.isDebuggable(TAG);
+ static final float INVALID_LUX = -1f;
+
+ private final SensorManager mSensorManager;
+ private final LightSensorListener mLightSensorListener;
+ private final Handler mHandler;
+ private final Injector mInjector;
+ private final AmbientFilter mAmbientFilter;
+
+ private Sensor mLightSensor;
+ private Sensor mRegisteredLightSensor = null;
+ private final int mLightSensorRate;
+
+ private final SensorEventListener mLightSensorEventListener = new SensorEventListener() {
+ @Override
+ public void onSensorChanged(SensorEvent event) {
+ long now = mInjector.getTime();
+ mAmbientFilter.addValue(TimeUnit.NANOSECONDS.toMillis(event.timestamp),
+ event.values[0]);
+ final float lux = mAmbientFilter.getEstimate(now);
+ mLightSensorListener.onAmbientLuxChange(lux);
+ }
+
+ @Override
+ public void onAccuracyChanged(Sensor sensor, int accuracy) {
+ // unused
+ }
+ };
+
+ LightSensorController(SensorManager sensorManager, Resources resources,
+ LightSensorListener listener, Handler handler) {
+ this(sensorManager, resources, listener, handler, new Injector());
+ }
+
+ @VisibleForTesting
+ LightSensorController(SensorManager sensorManager, Resources resources,
+ LightSensorListener listener, Handler handler, Injector injector) {
+ mSensorManager = sensorManager;
+ mLightSensorRate = injector.getLightSensorRate(resources);
+ mAmbientFilter = injector.getAmbientFilter(resources);
+ mLightSensorListener = listener;
+ mHandler = handler;
+ mInjector = injector;
+ }
+
+ void restart() {
+ if (mRegisteredLightSensor == mLightSensor) {
+ return;
+ }
+ if (mRegisteredLightSensor != null) {
+ stop();
+ }
+ if (mLightSensor == null) {
+ return;
+ }
+
+ mSensorManager.registerListener(mLightSensorEventListener,
+ mLightSensor, mLightSensorRate * 1000, mHandler);
+ mRegisteredLightSensor = mLightSensor;
+
+ if (DEBUG) {
+ Slog.d(TAG, "restart");
+ }
+ }
+
+ void stop() {
+ if (mRegisteredLightSensor == null) {
+ return;
+ }
+ mSensorManager.unregisterListener(mLightSensorEventListener);
+ mRegisteredLightSensor = null;
+ mAmbientFilter.clear();
+ mLightSensorListener.onAmbientLuxChange(INVALID_LUX);
+ if (DEBUG) {
+ Slog.d(TAG, "stop");
+ }
+ }
+
+ void configure(SensorData sensorData, int displayId) {
+ final int fallbackType = displayId == Display.DEFAULT_DISPLAY
+ ? Sensor.TYPE_LIGHT : SensorUtils.NO_FALLBACK;
+ mLightSensor = mInjector.getLightSensor(mSensorManager, sensorData, fallbackType);
+ }
+
+ void dump(PrintWriter writer) {
+ writer.println("LightSensorController");
+ writer.println(" mLightSensor=" + mLightSensor);
+ writer.println(" mRegisteredLightSensor=" + mRegisteredLightSensor);
+ }
+
+ static class Injector {
+ @Nullable
+ Sensor getLightSensor(SensorManager sensorManager, SensorData sensorData,
+ int fallbackType) {
+ return SensorUtils.findSensor(sensorManager, sensorData, fallbackType);
+ }
+
+ AmbientFilter getAmbientFilter(Resources resources) {
+ return AmbientFilterFactory.createBrightnessFilter(TAG, resources);
+ }
+
+ int getLightSensorRate(Resources resources) {
+ return resources.getInteger(R.integer.config_autoBrightnessLightSensorRate);
+ }
+
+ // should be consistent with SensorEvent.timestamp
+ long getTime() {
+ return SystemClock.elapsedRealtime();
+ }
+ }
+
+ interface LightSensorListener {
+ void onAmbientLuxChange(float ambientLux);
+ }
+}
diff --git a/services/core/java/com/android/server/flags/services.aconfig b/services/core/java/com/android/server/flags/services.aconfig
index 9bbcb0c..d387828 100644
--- a/services/core/java/com/android/server/flags/services.aconfig
+++ b/services/core/java/com/android/server/flags/services.aconfig
@@ -28,3 +28,10 @@
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ namespace: "wear_frameworks"
+ name: "optional_background_install_control"
+ description: "Enable BackgroundInstallControl based on system feature to prevent it from starting on form factors."
+ bug: "340928990"
+}
diff --git a/services/core/java/com/android/server/inputmethod/SecureSettingsWrapper.java b/services/core/java/com/android/server/inputmethod/SecureSettingsWrapper.java
index 559b625..4764e4f 100644
--- a/services/core/java/com/android/server/inputmethod/SecureSettingsWrapper.java
+++ b/services/core/java/com/android/server/inputmethod/SecureSettingsWrapper.java
@@ -44,6 +44,32 @@
@Nullable
private static volatile ContentResolver sContentResolver = null;
+ private static volatile boolean sTestMode = false;
+
+ /**
+ * Can be called from unit tests to start the test mode, where a fake implementation will be
+ * used instead.
+ *
+ * <p>The fake implementation is just an {@link ArrayMap}. By default it is empty, and the data
+ * written can be read back later.</p>
+ */
+ @AnyThread
+ static void startTestMode() {
+ sTestMode = true;
+ }
+
+ /**
+ * Can be called from unit tests to end the test mode, where a fake implementation will be used
+ * instead.
+ */
+ @AnyThread
+ static void endTestMode() {
+ synchronized (sUserMap) {
+ sUserMap.clear();
+ }
+ sTestMode = false;
+ }
+
/**
* Not intended to be instantiated.
*/
@@ -78,6 +104,52 @@
int getInt(String key, int defaultValue);
}
+ private static class FakeReaderWriterImpl implements ReaderWriter {
+ @GuardedBy("mNonPersistentKeyValues")
+ private final ArrayMap<String, String> mNonPersistentKeyValues = new ArrayMap<>();
+
+ @AnyThread
+ @Override
+ public void putString(String key, String value) {
+ synchronized (mNonPersistentKeyValues) {
+ mNonPersistentKeyValues.put(key, value);
+ }
+ }
+
+ @AnyThread
+ @Nullable
+ @Override
+ public String getString(String key, String defaultValue) {
+ synchronized (mNonPersistentKeyValues) {
+ if (mNonPersistentKeyValues.containsKey(key)) {
+ final String result = mNonPersistentKeyValues.get(key);
+ return result != null ? result : defaultValue;
+ }
+ return defaultValue;
+ }
+ }
+
+ @AnyThread
+ @Override
+ public void putInt(String key, int value) {
+ synchronized (mNonPersistentKeyValues) {
+ mNonPersistentKeyValues.put(key, String.valueOf(value));
+ }
+ }
+
+ @AnyThread
+ @Override
+ public int getInt(String key, int defaultValue) {
+ synchronized (mNonPersistentKeyValues) {
+ if (mNonPersistentKeyValues.containsKey(key)) {
+ final String result = mNonPersistentKeyValues.get(key);
+ return result != null ? Integer.parseInt(result) : defaultValue;
+ }
+ return defaultValue;
+ }
+ }
+ }
+
private static class UnlockedUserImpl implements ReaderWriter {
@UserIdInt
private final int mUserId;
@@ -200,6 +272,9 @@
private static ReaderWriter createImpl(@NonNull UserManagerInternal userManagerInternal,
@UserIdInt int userId) {
+ if (sTestMode) {
+ return new FakeReaderWriterImpl();
+ }
return userManagerInternal.isUserUnlockingOrUnlocked(userId)
? new UnlockedUserImpl(userId, sContentResolver)
: new LockedUserImpl(userId, sContentResolver);
@@ -234,6 +309,9 @@
return readerWriter;
}
}
+ if (sTestMode) {
+ return putOrGet(userId, new FakeReaderWriterImpl());
+ }
final UserManagerInternal userManagerInternal =
LocalServices.getService(UserManagerInternal.class);
if (!userManagerInternal.exists(userId)) {
@@ -276,6 +354,10 @@
*/
@AnyThread
static void onUserStarting(@UserIdInt int userId) {
+ if (sTestMode) {
+ putOrGet(userId, new FakeReaderWriterImpl());
+ return;
+ }
putOrGet(userId, createImpl(LocalServices.getService(UserManagerInternal.class), userId));
}
@@ -286,6 +368,10 @@
*/
@AnyThread
static void onUserUnlocking(@UserIdInt int userId) {
+ if (sTestMode) {
+ putOrGet(userId, new FakeReaderWriterImpl());
+ return;
+ }
final ReaderWriter readerWriter = new UnlockedUserImpl(userId, sContentResolver);
putOrGet(userId, readerWriter);
}
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 22b33dd..ae3a2afb 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -254,9 +254,6 @@
private static final String MIGRATED_SP_CE_ONLY = "migrated_all_users_to_sp_and_bound_ce";
private static final String MIGRATED_SP_FULL = "migrated_all_users_to_sp_and_bound_keys";
- private static final boolean FIX_UNLOCKED_DEVICE_REQUIRED_KEYS =
- android.security.Flags.fixUnlockedDeviceRequiredKeysV2();
-
// Duration that LockSettingsService will store the gatekeeper password for. This allows
// multiple biometric enrollments without prompting the user to enter their password via
// ConfirmLockPassword/ConfirmLockPattern multiple times. This needs to be at least the duration
@@ -670,7 +667,6 @@
mActivityManager = injector.getActivityManager();
IntentFilter filter = new IntentFilter();
- filter.addAction(Intent.ACTION_USER_ADDED);
filter.addAction(Intent.ACTION_USER_STARTING);
filter.addAction(Intent.ACTION_LOCALE_CHANGED);
injector.getContext().registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter,
@@ -909,13 +905,7 @@
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- if (Intent.ACTION_USER_ADDED.equals(intent.getAction())) {
- if (!FIX_UNLOCKED_DEVICE_REQUIRED_KEYS) {
- // Notify keystore that a new user was added.
- final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
- AndroidKeyStoreMaintenance.onUserAdded(userHandle);
- }
- } else if (Intent.ACTION_USER_STARTING.equals(intent.getAction())) {
+ if (Intent.ACTION_USER_STARTING.equals(intent.getAction())) {
final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
mStorage.prefetchUser(userHandle);
} else if (Intent.ACTION_LOCALE_CHANGED.equals(intent.getAction())) {
@@ -1130,32 +1120,14 @@
// Note: if this migration gets interrupted (e.g. by the device powering off), there
// shouldn't be a problem since this will run again on the next boot, and
// setCeStorageProtection() and initKeystoreSuperKeys(..., true) are idempotent.
- if (FIX_UNLOCKED_DEVICE_REQUIRED_KEYS) {
- if (!getBoolean(MIGRATED_SP_FULL, false, 0)) {
- for (UserInfo user : mUserManager.getAliveUsers()) {
- removeStateForReusedUserIdIfNecessary(user.id, user.serialNumber);
- synchronized (mSpManager) {
- migrateUserToSpWithBoundKeysLocked(user.id);
- }
+ if (!getBoolean(MIGRATED_SP_FULL, false, 0)) {
+ for (UserInfo user : mUserManager.getAliveUsers()) {
+ removeStateForReusedUserIdIfNecessary(user.id, user.serialNumber);
+ synchronized (mSpManager) {
+ migrateUserToSpWithBoundKeysLocked(user.id);
}
- setBoolean(MIGRATED_SP_FULL, true, 0);
}
- } else {
- if (getString(MIGRATED_SP_CE_ONLY, null, 0) == null) {
- for (UserInfo user : mUserManager.getAliveUsers()) {
- removeStateForReusedUserIdIfNecessary(user.id, user.serialNumber);
- synchronized (mSpManager) {
- migrateUserToSpWithBoundCeKeyLocked(user.id);
- }
- }
- setString(MIGRATED_SP_CE_ONLY, "true", 0);
- }
-
- if (getBoolean(MIGRATED_SP_FULL, false, 0)) {
- // The FIX_UNLOCKED_DEVICE_REQUIRED_KEYS flag was enabled but then got disabled.
- // Ensure the full migration runs again the next time the flag is enabled...
- setBoolean(MIGRATED_SP_FULL, false, 0);
- }
+ setBoolean(MIGRATED_SP_FULL, true, 0);
}
mThirdPartyAppsStarted = true;
@@ -1163,30 +1135,6 @@
}
@GuardedBy("mSpManager")
- private void migrateUserToSpWithBoundCeKeyLocked(@UserIdInt int userId) {
- if (isUserSecure(userId)) {
- Slogf.d(TAG, "User %d is secured; no migration needed", userId);
- return;
- }
- long protectorId = getCurrentLskfBasedProtectorId(userId);
- if (protectorId == SyntheticPasswordManager.NULL_PROTECTOR_ID) {
- Slogf.i(TAG, "Migrating unsecured user %d to SP-based credential", userId);
- initializeSyntheticPassword(userId);
- } else {
- Slogf.i(TAG, "Existing unsecured user %d has a synthetic password; re-encrypting CE " +
- "key with it", userId);
- AuthenticationResult result = mSpManager.unlockLskfBasedProtector(
- getGateKeeperService(), protectorId, LockscreenCredential.createNone(), userId,
- null);
- if (result.syntheticPassword == null) {
- Slogf.wtf(TAG, "Failed to unwrap synthetic password for unsecured user %d", userId);
- return;
- }
- setCeStorageProtection(userId, result.syntheticPassword);
- }
- }
-
- @GuardedBy("mSpManager")
private void migrateUserToSpWithBoundKeysLocked(@UserIdInt int userId) {
if (isUserSecure(userId)) {
Slogf.d(TAG, "User %d is secured; no migration needed", userId);
@@ -1496,11 +1444,6 @@
}
@VisibleForTesting /** Note: this method is overridden in unit tests */
- void setKeystorePassword(byte[] password, int userHandle) {
- AndroidKeyStoreMaintenance.onUserPasswordChanged(userHandle, password);
- }
-
- @VisibleForTesting /** Note: this method is overridden in unit tests */
void initKeystoreSuperKeys(@UserIdInt int userId, SyntheticPassword sp, boolean allowExisting) {
final byte[] password = sp.deriveKeyStorePassword();
try {
@@ -2237,9 +2180,7 @@
return;
}
onSyntheticPasswordUnlocked(userId, result.syntheticPassword);
- if (FIX_UNLOCKED_DEVICE_REQUIRED_KEYS) {
- unlockKeystore(userId, result.syntheticPassword);
- }
+ unlockKeystore(userId, result.syntheticPassword);
unlockCeStorage(userId, result.syntheticPassword);
}
}
@@ -2545,9 +2486,7 @@
// long time, so for now we keep doing it just in case it's ever important. Don't wait
// until initKeystoreSuperKeys() to do this; that can be delayed if the user is being
// created during early boot, and maybe something will use Keystore before then.
- if (FIX_UNLOCKED_DEVICE_REQUIRED_KEYS) {
- AndroidKeyStoreMaintenance.onUserAdded(userId);
- }
+ AndroidKeyStoreMaintenance.onUserAdded(userId);
synchronized (mUserCreationAndRemovalLock) {
// During early boot, don't actually create the synthetic password yet, but rather
@@ -2973,9 +2912,7 @@
LockscreenCredential.createNone(), sp, userId);
setCurrentLskfBasedProtectorId(protectorId, userId);
setCeStorageProtection(userId, sp);
- if (FIX_UNLOCKED_DEVICE_REQUIRED_KEYS) {
- initKeystoreSuperKeys(userId, sp, /* allowExisting= */ false);
- }
+ initKeystoreSuperKeys(userId, sp, /* allowExisting= */ false);
onSyntheticPasswordCreated(userId, sp);
Slogf.i(TAG, "Successfully initialized synthetic password for user %d", userId);
return sp;
@@ -3090,9 +3027,6 @@
if (!mSpManager.hasSidForUser(userId)) {
mSpManager.newSidForUser(getGateKeeperService(), sp, userId);
mSpManager.verifyChallenge(getGateKeeperService(), sp, 0L, userId);
- if (!FIX_UNLOCKED_DEVICE_REQUIRED_KEYS) {
- setKeystorePassword(sp.deriveKeyStorePassword(), userId);
- }
}
} else {
// Cache all profile password if they use unified challenge. This will later be used to
@@ -3103,11 +3037,7 @@
gateKeeperClearSecureUserId(userId);
unlockCeStorage(userId, sp);
unlockKeystore(userId, sp);
- if (FIX_UNLOCKED_DEVICE_REQUIRED_KEYS) {
- AndroidKeyStoreMaintenance.onUserLskfRemoved(userId);
- } else {
- setKeystorePassword(null, userId);
- }
+ AndroidKeyStoreMaintenance.onUserLskfRemoved(userId);
removeBiometricsForUser(userId);
}
setCurrentLskfBasedProtectorId(newProtectorId, userId);
diff --git a/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java b/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
index 3673eb0..56b93e8 100644
--- a/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
+++ b/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
@@ -839,6 +839,13 @@
+ "Disallowed route: "
+ route);
}
+
+ if (route.isSystemRouteType()) {
+ throw new SecurityException(
+ "Only the system is allowed to publish routes with system route types. "
+ + "Disallowed route: "
+ + route);
+ }
}
Connection connection = mConnectionRef.get();
diff --git a/services/core/java/com/android/server/notification/CustomManualConditionProvider.java b/services/core/java/com/android/server/notification/CustomManualConditionProvider.java
new file mode 100644
index 0000000..9531c5e
--- /dev/null
+++ b/services/core/java/com/android/server/notification/CustomManualConditionProvider.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.notification;
+
+import android.net.Uri;
+import android.service.notification.ZenModeConfig;
+
+import java.io.PrintWriter;
+
+/**
+ * Condition provider used for custom manual rules (i.e. user-created rules without an automatic
+ * trigger).
+ */
+public class CustomManualConditionProvider extends SystemConditionProviderService {
+
+ private static final String SIMPLE_NAME = CustomManualConditionProvider.class.getSimpleName();
+
+ @Override
+ public boolean isValidConditionId(Uri id) {
+ return ZenModeConfig.isValidCustomManualConditionId(id);
+ }
+
+ @Override
+ public void onBootComplete() {
+ // Nothing to do.
+ }
+
+ @Override
+ public void onConnected() {
+ // No need to keep subscriptions because we won't ever call notifyConditions
+ }
+
+ @Override
+ public void onSubscribe(Uri conditionId) {
+ // No need to keep subscriptions because we won't ever call notifyConditions
+ }
+
+ @Override
+ public void onUnsubscribe(Uri conditionId) {
+ // No need to keep subscriptions because we won't ever call notifyConditions
+ }
+
+ @Override
+ public void dump(PrintWriter pw, NotificationManagerService.DumpFilter filter) {
+ pw.print(" "); pw.print(SIMPLE_NAME); pw.println(": ENABLED");
+ }
+}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index b436c8b..f297708 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -46,6 +46,10 @@
import static android.app.Notification.FLAG_ONLY_ALERT_ONCE;
import static android.app.Notification.FLAG_USER_INITIATED_JOB;
import static android.app.NotificationChannel.CONVERSATION_CHANNEL_ID_FORMAT;
+import static android.app.NotificationChannel.NEWS_ID;
+import static android.app.NotificationChannel.PROMOTIONS_ID;
+import static android.app.NotificationChannel.RECS_ID;
+import static android.app.NotificationChannel.SOCIAL_MEDIA_ID;
import static android.app.NotificationManager.ACTION_APP_BLOCK_STATE_CHANGED;
import static android.app.NotificationManager.ACTION_AUTOMATIC_ZEN_RULE_STATUS_CHANGED;
import static android.app.NotificationManager.ACTION_CONSOLIDATED_NOTIFICATION_POLICY_CHANGED;
@@ -98,6 +102,11 @@
import static android.os.UserHandle.USER_ALL;
import static android.os.UserHandle.USER_NULL;
import static android.os.UserHandle.USER_SYSTEM;
+import static android.service.notification.Adjustment.KEY_TYPE;
+import static android.service.notification.Adjustment.TYPE_CONTENT_RECOMMENDATION;
+import static android.service.notification.Adjustment.TYPE_NEWS;
+import static android.service.notification.Adjustment.TYPE_PROMOTION;
+import static android.service.notification.Adjustment.TYPE_SOCIAL_MEDIA;
import static android.service.notification.Flags.callstyleCallbackApi;
import static android.service.notification.Flags.redactSensitiveNotificationsFromUntrustedListeners;
import static android.service.notification.Flags.redactSensitiveNotificationsBigTextStyle;
@@ -458,7 +467,8 @@
Adjustment.KEY_IMPORTANCE_PROPOSAL,
Adjustment.KEY_SENSITIVE_CONTENT,
Adjustment.KEY_RANKING_SCORE,
- Adjustment.KEY_NOT_CONVERSATION
+ Adjustment.KEY_NOT_CONVERSATION,
+ Adjustment.KEY_TYPE
};
static final String[] NON_BLOCKABLE_DEFAULT_ROLES = new String[] {
@@ -1023,7 +1033,7 @@
summary.getSbn().getNotification().color = summaryAttr.iconColor;
summary.getSbn().getNotification().visibility = summaryAttr.visibility;
mHandler.post(new EnqueueNotificationRunnable(userId, summary, isAppForeground,
- mPostNotificationTrackerFactory.newTracker(null)));
+ /* isAppProvided= */ false, mPostNotificationTrackerFactory.newTracker(null)));
}
}
@@ -1650,7 +1660,7 @@
// Force isAppForeground true here, because for sysui's purposes we
// want to adjust the flag behaviour.
mHandler.post(new EnqueueNotificationRunnable(r.getUser().getIdentifier(),
- r, true /* isAppForeground*/,
+ r, /* isAppForeground= */ true , /* isAppProvided= */ false,
mPostNotificationTrackerFactory.newTracker(null)));
}
}
@@ -1681,7 +1691,7 @@
// want to be able to adjust the flag behaviour.
mHandler.post(
new EnqueueNotificationRunnable(r.getUser().getIdentifier(), r,
- /* foreground= */ true,
+ /* foreground= */ true, /* isAppProvided= */ false,
mPostNotificationTrackerFactory.newTracker(null)));
}
}
@@ -2706,7 +2716,7 @@
enqueueNotificationInternal(r.getSbn().getPackageName(), r.getSbn().getOpPkg(),
r.getSbn().getUid(), r.getSbn().getInitialPid(), r.getSbn().getTag(),
r.getSbn().getId(), r.getSbn().getNotification(), userId, muteOnReturn,
- false /* byForegroundService */);
+ /* byForegroundService= */ false, /* isAppProvided= */ false);
} catch (Exception e) {
Slog.e(TAG, "Cannot un-snooze notification", e);
}
@@ -2851,6 +2861,7 @@
final boolean isAppForeground =
mActivityManager.getPackageImportance(pkg) == IMPORTANCE_FOREGROUND;
mHandler.post(new EnqueueNotificationRunnable(userId, r, isAppForeground,
+ /* isAppProvided= */ false,
mPostNotificationTrackerFactory.newTracker(null)));
}
}
@@ -3763,7 +3774,7 @@
Notification notification, int userId) throws RemoteException {
enqueueNotificationInternal(pkg, opPkg, Binder.getCallingUid(),
Binder.getCallingPid(), tag, id, notification, userId,
- false /* byForegroundService */);
+ /* byForegroundService= */ false, /* isAppProvided= */ true);
}
@Override
@@ -6608,6 +6619,30 @@
for (String removeKey : toRemove) {
adjustments.remove(removeKey);
}
+ if (android.service.notification.Flags.notificationClassification()
+ && adjustments.containsKey(KEY_TYPE)) {
+ NotificationChannel newChannel = null;
+ int type = adjustments.getInt(KEY_TYPE);
+ if (TYPE_NEWS == type) {
+ newChannel = mPreferencesHelper.getNotificationChannel(
+ r.getSbn().getPackageName(), r.getUid(), NEWS_ID, false);
+ } else if (TYPE_PROMOTION == type) {
+ newChannel = mPreferencesHelper.getNotificationChannel(
+ r.getSbn().getPackageName(), r.getUid(), PROMOTIONS_ID, false);
+ } else if (TYPE_SOCIAL_MEDIA == type) {
+ newChannel = mPreferencesHelper.getNotificationChannel(
+ r.getSbn().getPackageName(), r.getUid(), SOCIAL_MEDIA_ID, false);
+ } else if (TYPE_CONTENT_RECOMMENDATION == type) {
+ newChannel = mPreferencesHelper.getNotificationChannel(
+ r.getSbn().getPackageName(), r.getUid(), RECS_ID, false);
+ }
+ if (newChannel == null) {
+ adjustments.remove(KEY_TYPE);
+ } else {
+ // swap app provided type with the real thing
+ adjustments.putParcelable(KEY_TYPE, newChannel);
+ }
+ }
r.addAdjustment(adjustment);
if (adjustment.getSignals().containsKey(Adjustment.KEY_SENSITIVE_CONTENT)) {
logSensitiveAdjustmentReceived(isPosted,
@@ -7025,7 +7060,7 @@
public void enqueueNotification(String pkg, String opPkg, int callingUid, int callingPid,
String tag, int id, Notification notification, int userId) {
enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification,
- userId, false /* byForegroundService */);
+ userId, /* byForegroundService= */ false , /* isAppProvided= */ true);
}
@Override
@@ -7033,7 +7068,7 @@
String tag, int id, Notification notification, int userId,
boolean byForegroundService) {
enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification,
- userId, byForegroundService);
+ userId, byForegroundService, /* isAppProvided= */ true);
}
@Override
@@ -7245,7 +7280,8 @@
r.getSbn().getInitialPid(), r.getSbn().getTag(),
r.getSbn().getId(), r.getNotification(),
r.getSbn().getUserId(), /* postSilently= */ true,
- /* byForegroundService= */ false);
+ /* byForegroundService= */ false,
+ /* isAppProvided= */ false);
}
int getNumNotificationChannelsForPackage(String pkg, int uid, boolean includeDeleted) {
@@ -7306,19 +7342,21 @@
void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid,
final int callingPid, final String tag, final int id, final Notification notification,
- int incomingUserId, boolean byForegroundService) {
+ int incomingUserId, boolean byForegroundService, boolean isAppProvided) {
enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification,
- incomingUserId, false /* postSilently */, byForegroundService);
+ incomingUserId, false /* postSilently */, byForegroundService, isAppProvided);
}
void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid,
final int callingPid, final String tag, final int id, final Notification notification,
- int incomingUserId, boolean postSilently, boolean byForegroundService) {
+ int incomingUserId, boolean postSilently, boolean byForegroundService,
+ boolean isAppProvided) {
PostNotificationTracker tracker = acquireWakeLockForPost(pkg, callingUid);
boolean enqueued = false;
try {
enqueued = enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id,
- notification, incomingUserId, postSilently, tracker, byForegroundService);
+ notification, incomingUserId, postSilently, tracker, byForegroundService,
+ isAppProvided);
} finally {
if (!enqueued) {
tracker.cancel();
@@ -7344,7 +7382,7 @@
private boolean enqueueNotificationInternal(final String pkg, final String opPkg, //HUI
final int callingUid, final int callingPid, final String tag, final int id,
final Notification notification, int incomingUserId, boolean postSilently,
- PostNotificationTracker tracker, boolean byForegroundService) {
+ PostNotificationTracker tracker, boolean byForegroundService, boolean isAppProvided) {
if (DBG) {
Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id
+ " notification=" + notification);
@@ -7545,7 +7583,8 @@
// Need escalated privileges to get package importance.
final int packageImportance = getPackageImportanceWithIdentity(pkg);
boolean isAppForeground = packageImportance == IMPORTANCE_FOREGROUND;
- mHandler.post(new EnqueueNotificationRunnable(userId, r, isAppForeground, tracker));
+ mHandler.post(new EnqueueNotificationRunnable(userId, r, isAppForeground,
+ /* isAppProvided= */ isAppProvided, tracker));
return true;
}
@@ -7925,6 +7964,7 @@
mHandler.post(
new EnqueueNotificationRunnable(
r.getUser().getIdentifier(), r, isAppForeground,
+ /* isAppProvided= */ false,
mPostNotificationTrackerFactory.newTracker(null)));
}
}
@@ -8495,13 +8535,15 @@
private final NotificationRecord r;
private final int userId;
private final boolean isAppForeground;
+ private final boolean isAppProvided;
private final PostNotificationTracker mTracker;
EnqueueNotificationRunnable(int userId, NotificationRecord r, boolean foreground,
- PostNotificationTracker tracker) {
+ boolean isAppProvided, PostNotificationTracker tracker) {
this.userId = userId;
this.r = r;
this.isAppForeground = foreground;
+ this.isAppProvided = isAppProvided;
this.mTracker = checkNotNull(tracker);
}
@@ -8586,9 +8628,10 @@
if (old != null) {
enqueueStatus = EVENTLOG_ENQUEUE_STATUS_UPDATE;
}
+ int appProvided = isAppProvided ? 1 : 0;
EventLogTags.writeNotificationEnqueue(callingUid, callingPid,
pkg, id, tag, userId, notification.toString(),
- enqueueStatus);
+ enqueueStatus, appProvided);
}
// tell the assistant service about the notification
@@ -8748,7 +8791,7 @@
// was not autogrouped onPost, to avoid an unnecessary sort.
// We add the autogroup key to the notification without a
// sort here, and it'll be sorted below with extractSignals.
- addAutogroupKeyLocked(key, /*requestSort=*/false);
+ addAutogroupKeyLocked(key, /* requestSort= */false);
}
}
}
@@ -11373,7 +11416,7 @@
record.getNotification().flags |= FLAG_ONLY_ALERT_ONCE;
mHandler.post(new EnqueueNotificationRunnable(record.getUser().getIdentifier(),
- record, isAppForeground,
+ record, isAppForeground, /* isAppProvided= */ false,
mPostNotificationTrackerFactory.newTracker(null)));
}
}
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index 0c6a6c8..0d4bdf6 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -710,7 +710,8 @@
if (signals.containsKey(Adjustment.KEY_SNOOZE_CRITERIA)) {
final ArrayList<SnoozeCriterion> snoozeCriterionList =
adjustment.getSignals().getParcelableArrayList(
- Adjustment.KEY_SNOOZE_CRITERIA, android.service.notification.SnoozeCriterion.class);
+ Adjustment.KEY_SNOOZE_CRITERIA,
+ android.service.notification.SnoozeCriterion.class);
setSnoozeCriteria(snoozeCriterionList);
EventLogTags.writeNotificationAdjusted(getKey(), Adjustment.KEY_SNOOZE_CRITERIA,
snoozeCriterionList.toString());
@@ -736,7 +737,8 @@
}
if (signals.containsKey(Adjustment.KEY_CONTEXTUAL_ACTIONS)) {
setSystemGeneratedSmartActions(
- signals.getParcelableArrayList(Adjustment.KEY_CONTEXTUAL_ACTIONS, android.app.Notification.Action.class));
+ signals.getParcelableArrayList(Adjustment.KEY_CONTEXTUAL_ACTIONS,
+ android.app.Notification.Action.class));
EventLogTags.writeNotificationAdjusted(getKey(),
Adjustment.KEY_CONTEXTUAL_ACTIONS,
getSystemGeneratedSmartActions().toString());
@@ -778,6 +780,14 @@
Adjustment.KEY_SENSITIVE_CONTENT,
Boolean.toString(mSensitiveContent));
}
+ if (android.service.notification.Flags.notificationClassification()
+ && signals.containsKey(Adjustment.KEY_TYPE)) {
+ updateNotificationChannel(signals.getParcelable(Adjustment.KEY_TYPE,
+ NotificationChannel.class));
+ EventLogTags.writeNotificationAdjusted(getKey(),
+ Adjustment.KEY_TYPE,
+ mChannel.getId());
+ }
if (!signals.isEmpty() && adjustment.getIssuer() != null) {
mAdjustmentIssuer = adjustment.getIssuer();
}
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index 309e945..9ee05d8 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -22,11 +22,14 @@
import static android.app.NotificationManager.BUBBLE_PREFERENCE_ALL;
import static android.app.NotificationManager.BUBBLE_PREFERENCE_NONE;
import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
+import static android.app.NotificationManager.IMPORTANCE_LOW;
import static android.app.NotificationManager.IMPORTANCE_MAX;
import static android.app.NotificationManager.IMPORTANCE_NONE;
import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
import static android.os.UserHandle.USER_SYSTEM;
+import static android.service.notification.Flags.notificationClassification;
+
import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_CHANNEL_GROUP_PREFERENCES;
import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES;
import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_PREFERENCES;
@@ -514,6 +517,10 @@
Slog.e(TAG, "createDefaultChannelIfNeededLocked - Exception: " + e);
}
+ if (notificationClassification()) {
+ addReservedChannelsLocked(r);
+ }
+
if (r.uid == UNKNOWN_UID) {
if (Flags.persistIncompleteRestoreData()) {
r.userId = userId;
@@ -603,6 +610,40 @@
return true;
}
+ private void addReservedChannelsLocked(PackagePreferences p) {
+ if (!p.channels.containsKey(NotificationChannel.PROMOTIONS_ID)) {
+ NotificationChannel channel = new NotificationChannel(
+ NotificationChannel.PROMOTIONS_ID,
+ mContext.getString(R.string.promotional_notification_channel_label),
+ IMPORTANCE_LOW);
+ p.channels.put(channel.getId(), channel);
+ }
+
+ if (!p.channels.containsKey(NotificationChannel.RECS_ID)) {
+ NotificationChannel channel = new NotificationChannel(
+ NotificationChannel.RECS_ID,
+ mContext.getString(R.string.recs_notification_channel_label),
+ IMPORTANCE_LOW);
+ p.channels.put(channel.getId(), channel);
+ }
+
+ if (!p.channels.containsKey(NotificationChannel.NEWS_ID)) {
+ NotificationChannel channel = new NotificationChannel(
+ NotificationChannel.NEWS_ID,
+ mContext.getString(R.string.news_notification_channel_label),
+ IMPORTANCE_LOW);
+ p.channels.put(channel.getId(), channel);
+ }
+
+ if (!p.channels.containsKey(NotificationChannel.SOCIAL_MEDIA_ID)) {
+ NotificationChannel channel = new NotificationChannel(
+ NotificationChannel.SOCIAL_MEDIA_ID,
+ mContext.getString(R.string.social_notification_channel_label),
+ IMPORTANCE_LOW);
+ p.channels.put(channel.getId(), channel);
+ }
+ }
+
public void writeXml(TypedXmlSerializer out, boolean forBackup, int userId) throws IOException {
out.startTag(null, TAG_RANKING);
out.attributeInt(null, ATT_VERSION, XML_VERSION);
@@ -1801,7 +1842,7 @@
public boolean onlyHasDefaultChannel(String pkg, int uid) {
synchronized (mPackagePreferences) {
PackagePreferences r = getOrCreatePackagePreferencesLocked(pkg, uid);
- if (r.channels.size() == 1
+ if (r.channels.size() == (notificationClassification() ? 5 : 1)
&& r.channels.containsKey(NotificationChannel.DEFAULT_CHANNEL_ID)) {
return true;
}
@@ -2611,6 +2652,7 @@
context.getResources().getString(
R.string.default_notification_channel_label));
}
+ // TODO (b/346396459): Localize all reserved channels
}
}
}
diff --git a/services/core/java/com/android/server/notification/TimeToLiveHelper.java b/services/core/java/com/android/server/notification/TimeToLiveHelper.java
index 2facab7..a4460b2 100644
--- a/services/core/java/com/android/server/notification/TimeToLiveHelper.java
+++ b/services/core/java/com/android/server/notification/TimeToLiveHelper.java
@@ -54,13 +54,17 @@
private final AlarmManager mAm;
@VisibleForTesting
+ @GuardedBy("mLock")
final TreeSet<Pair<Long, String>> mKeys;
+ final Object mLock = new Object();
public TimeToLiveHelper(NotificationManagerPrivate nm, Context context) {
mContext = context;
mNm = nm;
mAm = context.getSystemService(AlarmManager.class);
- mKeys = new TreeSet<>((left, right) -> Long.compare(left.first, right.first));
+ synchronized (mLock) {
+ mKeys = new TreeSet<>((left, right) -> Long.compare(left.first, right.first));
+ }
IntentFilter timeoutFilter = new IntentFilter(ACTION);
timeoutFilter.addDataScheme(SCHEME_TIMEOUT);
@@ -73,7 +77,9 @@
}
void dump(PrintWriter pw, String indent) {
- pw.println(indent + "mKeys " + mKeys);
+ synchronized (mLock) {
+ pw.println(indent + "mKeys " + mKeys);
+ }
}
private @NonNull PendingIntent getAlarmPendingIntent(String nextKey, int flags) {
@@ -93,30 +99,35 @@
@VisibleForTesting
void scheduleTimeoutLocked(NotificationRecord record, long currentTime) {
- removeMatchingEntry(record.getKey());
+ synchronized (mLock) {
+ removeMatchingEntry(record.getKey());
- final long timeoutAfter = currentTime + record.getNotification().getTimeoutAfter();
- if (record.getNotification().getTimeoutAfter() > 0) {
- final Long currentEarliestTime = mKeys.isEmpty() ? null : mKeys.first().first;
+ final long timeoutAfter = currentTime + record.getNotification().getTimeoutAfter();
+ if (record.getNotification().getTimeoutAfter() > 0) {
+ final Long currentEarliestTime = mKeys.isEmpty() ? null : mKeys.first().first;
- // Maybe replace alarm with an earlier one
- if (currentEarliestTime == null || timeoutAfter < currentEarliestTime) {
- if (currentEarliestTime != null) {
- cancelFirstAlarm();
+ // Maybe replace alarm with an earlier one
+ if (currentEarliestTime == null || timeoutAfter < currentEarliestTime) {
+ if (currentEarliestTime != null) {
+ cancelFirstAlarm();
+ }
+ mKeys.add(Pair.create(timeoutAfter, record.getKey()));
+ maybeScheduleFirstAlarm();
+ } else {
+ mKeys.add(Pair.create(timeoutAfter, record.getKey()));
}
- mKeys.add(Pair.create(timeoutAfter, record.getKey()));
- maybeScheduleFirstAlarm();
- } else {
- mKeys.add(Pair.create(timeoutAfter, record.getKey()));
}
}
}
@VisibleForTesting
void cancelScheduledTimeoutLocked(NotificationRecord record) {
- removeMatchingEntry(record.getKey());
+ synchronized (mLock) {
+ removeMatchingEntry(record.getKey());
+ }
}
+ @GuardedBy("mLock")
private void removeMatchingEntry(String key) {
if (!mKeys.isEmpty() && key.equals(mKeys.first().second)) {
// cancel the first alarm, remove the first entry, maybe schedule the alarm for the new
@@ -139,11 +150,13 @@
}
}
+ @GuardedBy("mLock")
private void cancelFirstAlarm() {
final PendingIntent pi = getAlarmPendingIntent(mKeys.first().second, FLAG_CANCEL_CURRENT);
mAm.cancel(pi);
}
+ @GuardedBy("mLock")
private void maybeScheduleFirstAlarm() {
if (!mKeys.isEmpty()) {
final PendingIntent piNewFirst = getAlarmPendingIntent(mKeys.first().second,
@@ -162,13 +175,17 @@
return;
}
if (ACTION.equals(action)) {
- Pair<Long, String> earliest = mKeys.first();
- String key = intent.getStringExtra(EXTRA_KEY);
- if (!earliest.second.equals(key)) {
- Slog.wtf(TAG, "Alarm triggered but wasn't the earliest we were tracking");
+ String timeoutKey = null;
+ synchronized (mLock) {
+ Pair<Long, String> earliest = mKeys.first();
+ String key = intent.getStringExtra(EXTRA_KEY);
+ if (!earliest.second.equals(key)) {
+ Slog.wtf(TAG, "Alarm triggered but wasn't the earliest we were tracking");
+ }
+ removeMatchingEntry(key);
+ timeoutKey = earliest.second;
}
- removeMatchingEntry(key);
- mNm.timeoutNotification(earliest.second);
+ mNm.timeoutNotification(timeoutKey);
}
}
};
diff --git a/services/core/java/com/android/server/notification/ZenModeConditions.java b/services/core/java/com/android/server/notification/ZenModeConditions.java
index 02b5f97..3650536 100644
--- a/services/core/java/com/android/server/notification/ZenModeConditions.java
+++ b/services/core/java/com/android/server/notification/ZenModeConditions.java
@@ -58,6 +58,9 @@
if (mConditionProviders.isSystemProviderEnabled(ZenModeConfig.EVENT_PATH)) {
mConditionProviders.addSystemProvider(new EventConditionProvider());
}
+ if (mConditionProviders.isSystemProviderEnabled(ZenModeConfig.CUSTOM_MANUAL_PATH)) {
+ mConditionProviders.addSystemProvider(new CustomManualConditionProvider());
+ }
mConditionProviders.setCallback(this);
}
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 267291c..2e7295e 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -1134,6 +1134,15 @@
modified = true;
}
+ // Allow updating the CPS backing system rules (e.g. for custom manual -> schedule)
+ if (Flags.modesUi()
+ && (origin == UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI || origin == UPDATE_ORIGIN_USER)
+ && Objects.equals(rule.pkg, SystemZenRules.PACKAGE_ANDROID)
+ && !Objects.equals(rule.component, azr.getOwner())) {
+ rule.component = azr.getOwner();
+ modified = true;
+ }
+
if (!Objects.equals(rule.conditionId, azr.getConditionId())) {
rule.conditionId = azr.getConditionId();
modified = true;
diff --git a/services/core/java/com/android/server/pm/ResolveIntentHelper.java b/services/core/java/com/android/server/pm/ResolveIntentHelper.java
index 69490a8..5b4f310 100644
--- a/services/core/java/com/android/server/pm/ResolveIntentHelper.java
+++ b/services/core/java/com/android/server/pm/ResolveIntentHelper.java
@@ -126,10 +126,12 @@
userId, resolveForStart, /*allowDynamicSplits*/ true);
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
- var args = new SaferIntentUtils.IntentArgs(intent, resolvedType,
- false /* isReceiver */, resolveForStart, filterCallingUid, callingPid);
- args.platformCompat = mPlatformCompat;
- SaferIntentUtils.filterNonExportedComponents(args, query);
+ if (resolveForStart) {
+ var args = new SaferIntentUtils.IntentArgs(intent, resolvedType,
+ false /* isReceiver */, true, filterCallingUid, callingPid);
+ args.platformCompat = mPlatformCompat;
+ SaferIntentUtils.filterNonExportedComponents(args, query);
+ }
final boolean queryMayBeFiltered =
UserHandle.getAppId(filterCallingUid) >= Process.FIRST_APPLICATION_UID
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index db94d0e..d1d8993 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -5918,6 +5918,7 @@
return userData;
}
+ /** For testing only! Directly, unnaturally removes userId from list of users. */
@VisibleForTesting
void removeUserInfo(@UserIdInt int userId) {
synchronized (mUsersLock) {
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 28254d0..46e6546 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -274,7 +274,9 @@
mVirtualDeviceManagerInternal =
LocalServices.getService(VirtualDeviceManagerInternal.class);
}
- return mVirtualDeviceManagerInternal.getPersistentIdForDevice(deviceId);
+ return mVirtualDeviceManagerInternal == null
+ ? VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT
+ : mVirtualDeviceManagerInternal.getPersistentIdForDevice(deviceId);
}
@Override
diff --git a/services/core/java/com/android/server/power/ShutdownThread.java b/services/core/java/com/android/server/power/ShutdownThread.java
index 6b7f2fa..4b4e442 100644
--- a/services/core/java/com/android/server/power/ShutdownThread.java
+++ b/services/core/java/com/android/server/power/ShutdownThread.java
@@ -48,6 +48,7 @@
import android.os.VibrationEffect;
import android.os.Vibrator;
import android.os.vibrator.persistence.VibrationXmlParser;
+import android.provider.Settings;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.ArrayMap;
@@ -743,6 +744,11 @@
*/
@VisibleForTesting // For testing vibrations without shutting down device
void playShutdownVibration(Context context) {
+ if (mInjector.isShutdownVibrationDisabled(context)) {
+ Log.i(TAG, "Vibration disabled in config");
+ return;
+ }
+
Vibrator vibrator = mInjector.getVibrator(context);
if (!vibrator.hasVibrator()) {
return;
@@ -920,5 +926,14 @@
return context.getResources().getString(
com.android.internal.R.string.config_defaultShutdownVibrationFile);
}
+
+ public boolean isShutdownVibrationDisabled(Context context) {
+ boolean disabledInConfig = context.getResources().getBoolean(
+ com.android.internal.R.bool.config_disableShutdownVibrationInZen);
+ boolean isZenMode = Settings.Global.getInt(context.getContentResolver(),
+ Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_OFF)
+ != Settings.Global.ZEN_MODE_OFF;
+ return disabledInConfig && isZenMode;
+ }
}
}
diff --git a/services/core/java/com/android/server/power/stats/EnergyConsumerPowerStatsCollector.java b/services/core/java/com/android/server/power/stats/EnergyConsumerPowerStatsCollector.java
index 7f2f729..cace941 100644
--- a/services/core/java/com/android/server/power/stats/EnergyConsumerPowerStatsCollector.java
+++ b/services/core/java/com/android/server/power/stats/EnergyConsumerPowerStatsCollector.java
@@ -128,6 +128,16 @@
return null;
}
+ int voltageMv = mVoltageSupplier.getAsInt();
+ int averageVoltage = mLastVoltageMv != 0 ? (mLastVoltageMv + voltageMv) / 2 : voltageMv;
+ if (averageVoltage <= 0) {
+ Slog.wtf(TAG, "Unexpected battery voltage (" + voltageMv
+ + " mV) when querying energy consumers");
+ return null;
+ }
+
+ mLastVoltageMv = voltageMv;
+
EnergyConsumerResult[] energy =
mConsumedEnergyRetriever.getConsumedEnergy(mEnergyConsumerIds);
long consumedEnergy = 0;
@@ -151,15 +161,6 @@
return null;
}
- int voltageMv = mVoltageSupplier.getAsInt();
- if (voltageMv <= 0) {
- Slog.wtf(TAG, "Unexpected battery voltage (" + voltageMv
- + " mV) when querying energy consumers");
- voltageMv = 0;
- }
-
- int averageVoltage = mLastVoltageMv != 0 ? (mLastVoltageMv + voltageMv) / 2 : voltageMv;
- mLastVoltageMv = voltageMv;
mLayout.setConsumedEnergy(mPowerStats.stats, 0, uJtoUc(energyDelta, averageVoltage));
for (int i = mPowerStats.uidStats.size() - 1; i >= 0; i--) {
diff --git a/services/core/java/com/android/server/timezonedetector/OWNERS b/services/core/java/com/android/server/timezonedetector/OWNERS
index 485a0dd..dfa07d8 100644
--- a/services/core/java/com/android/server/timezonedetector/OWNERS
+++ b/services/core/java/com/android/server/timezonedetector/OWNERS
@@ -2,7 +2,7 @@
# This is the main list for platform time / time zone detection maintainers, for this dir and
# ultimately referenced by other OWNERS files for components maintained by the same team.
nfuller@google.com
+boullanger@google.com
jmorace@google.com
kanyinsola@google.com
-mingaleev@google.com
-narayan@google.com
+mingaleev@google.com
\ No newline at end of file
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index 3138a9e..ddbd809 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -1026,12 +1026,7 @@
continue;
}
- final boolean trusted;
- if (android.security.Flags.fixUnlockedDeviceRequiredKeysV2()) {
- trusted = getUserTrustStateInner(id) == TrustState.TRUSTED;
- } else {
- trusted = aggregateIsTrusted(id);
- }
+ final boolean trusted = getUserTrustStateInner(id) == TrustState.TRUSTED;
boolean showingKeyguard = true;
boolean biometricAuthenticated = false;
boolean currentUserIsUnlocked = false;
@@ -1092,19 +1087,15 @@
private void notifyKeystoreOfDeviceLockState(int userId, boolean isLocked) {
if (isLocked) {
- if (android.security.Flags.fixUnlockedDeviceRequiredKeysV2()) {
- // A profile with unified challenge is unlockable not by its own biometrics and
- // trust agents, but rather by those of the parent user. Therefore, when protecting
- // the profile's UnlockedDeviceRequired keys, we must use the parent's list of
- // biometric SIDs and weak unlock methods, not the profile's.
- int authUserId = mLockPatternUtils.isProfileWithUnifiedChallenge(userId)
- ? resolveProfileParent(userId) : userId;
+ // A profile with unified challenge is unlockable not by its own biometrics and
+ // trust agents, but rather by those of the parent user. Therefore, when protecting
+ // the profile's UnlockedDeviceRequired keys, we must use the parent's list of
+ // biometric SIDs and weak unlock methods, not the profile's.
+ int authUserId = mLockPatternUtils.isProfileWithUnifiedChallenge(userId)
+ ? resolveProfileParent(userId) : userId;
- mKeyStoreAuthorization.onDeviceLocked(userId, getBiometricSids(authUserId),
- isWeakUnlockMethodEnabled(authUserId));
- } else {
- mKeyStoreAuthorization.onDeviceLocked(userId, getBiometricSids(userId), false);
- }
+ mKeyStoreAuthorization.onDeviceLocked(userId, getBiometricSids(authUserId),
+ isWeakUnlockMethodEnabled(authUserId));
} else {
// Notify Keystore that the device is now unlocked for the user. Note that for unlocks
// with LSKF, this is redundant with the call from LockSettingsService which provides
diff --git a/services/core/java/com/android/server/vibrator/Vibration.java b/services/core/java/com/android/server/vibrator/Vibration.java
index 84c37180..6537228 100644
--- a/services/core/java/com/android/server/vibrator/Vibration.java
+++ b/services/core/java/com/android/server/vibrator/Vibration.java
@@ -69,6 +69,7 @@
CANCELLED_BY_USER(VibrationProto.CANCELLED_BY_USER),
CANCELLED_BY_UNKNOWN_REASON(VibrationProto.CANCELLED_BY_UNKNOWN_REASON),
CANCELLED_SUPERSEDED(VibrationProto.CANCELLED_SUPERSEDED),
+ CANCELLED_BY_APP_OPS(VibrationProto.CANCELLED_BY_APP_OPS),
IGNORED_ERROR_APP_OPS(VibrationProto.IGNORED_ERROR_APP_OPS),
IGNORED_ERROR_CANCELLING(VibrationProto.IGNORED_ERROR_CANCELLING),
IGNORED_ERROR_SCHEDULING(VibrationProto.IGNORED_ERROR_SCHEDULING),
diff --git a/services/core/java/com/android/server/vibrator/VibratorManagerService.java b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
index 3dcc7a6..7f60dc44 100644
--- a/services/core/java/com/android/server/vibrator/VibratorManagerService.java
+++ b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
@@ -193,6 +193,27 @@
}
};
+ @VisibleForTesting
+ final AppOpsManager.OnOpChangedInternalListener mAppOpsChangeListener =
+ new AppOpsManager.OnOpChangedInternalListener() {
+ @Override
+ public void onOpChanged(int op, String packageName) {
+ if (op != AppOpsManager.OP_VIBRATE) {
+ return;
+ }
+ synchronized (mLock) {
+ if (shouldCancelAppOpModeChangedLocked(mNextVibration)) {
+ clearNextVibrationLocked(
+ new Vibration.EndInfo(Vibration.Status.CANCELLED_BY_APP_OPS));
+ }
+ if (shouldCancelAppOpModeChangedLocked(mCurrentVibration)) {
+ mCurrentVibration.notifyCancelled(new Vibration.EndInfo(
+ Vibration.Status.CANCELLED_BY_APP_OPS), /* immediate= */ false);
+ }
+ }
+ }
+ };
+
static native long nativeInit(OnSyncedVibrationCompleteListener listener);
static native long nativeGetFinalizer();
@@ -238,6 +259,9 @@
mBatteryStatsService = injector.getBatteryStatsService();
mAppOps = mContext.getSystemService(AppOpsManager.class);
+ if (Flags.cancelByAppops()) {
+ mAppOps.startWatchingMode(AppOpsManager.OP_VIBRATE, null, mAppOpsChangeListener);
+ }
PowerManager pm = context.getSystemService(PowerManager.class);
mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*vibrator*");
@@ -1390,6 +1414,15 @@
}
@GuardedBy("mLock")
+ private boolean shouldCancelAppOpModeChangedLocked(@Nullable VibrationStepConductor conductor) {
+ if (conductor == null) {
+ return false;
+ }
+ return checkAppOpModeLocked(conductor.getVibration().callerInfo)
+ != AppOpsManager.MODE_ALLOWED;
+ }
+
+ @GuardedBy("mLock")
private void onAllVibratorsLocked(Consumer<VibratorController> consumer) {
for (int i = 0; i < mVibrators.size(); i++) {
consumer.accept(mVibrators.valueAt(i));
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 10243a7..9bc4389 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -158,7 +158,6 @@
import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_SIZE_COMPAT_MODE;
import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__STATE__NOT_LETTERBOXED;
import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__STATE__NOT_VISIBLE;
-import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
import static com.android.server.wm.ActivityRecord.State.DESTROYED;
@@ -807,9 +806,10 @@
final LetterboxUiController mLetterboxUiController;
/**
- * The policy for transparent activities
+ * App Compat Facade
*/
- final TransparentPolicy mTransparentPolicy;
+ @NonNull
+ final AppCompatController mAppCompatController;
/**
* The scale to fit at least one side of the activity to its parent. If the activity uses
@@ -1706,7 +1706,7 @@
if (isState(RESUMED)) {
newParent.setResumedActivity(this, "onParentChanged");
}
- mTransparentPolicy.start();
+ mAppCompatController.getTransparentPolicy().start();
}
if (rootTask != null && rootTask.topRunningActivity() == this) {
@@ -1908,7 +1908,7 @@
}
void updateLetterboxSurfaceIfNeeded(WindowState winHint, Transaction t) {
- mLetterboxUiController.updateLetterboxSurfaceIfNeeded(winHint, t);
+ mLetterboxUiController.updateLetterboxSurfaceIfNeeded(winHint, t, getPendingTransaction());
}
void updateLetterboxSurfaceIfNeeded(WindowState winHint) {
@@ -2144,8 +2144,8 @@
// Don't move below setOrientation(info.screenOrientation) since it triggers
// getOverrideOrientation that requires having mLetterboxUiController
// initialised.
- mTransparentPolicy = new TransparentPolicy(this, mWmService.mLetterboxConfiguration);
mLetterboxUiController = new LetterboxUiController(mWmService, this);
+ mAppCompatController = new AppCompatController(mWmService, this);
mCameraCompatControlEnabled = mWmService.mContext.getResources()
.getBoolean(R.bool.config_isCameraCompatControlForStretchedIssuesEnabled);
mResolveConfigHint = new TaskFragment.ConfigOverrideHint();
@@ -4505,6 +4505,7 @@
mTaskSupervisor.getActivityMetricsLogger().notifyActivityRemoved(this);
mTaskSupervisor.mStoppingActivities.remove(this);
mLetterboxUiController.destroy();
+ mAppCompatController.getTransparentPolicy().stop();
// Defer removal of this activity when either a child is animating, or app transition is on
// going. App transition animation might be applied on the parent task not on the activity,
@@ -8108,13 +8109,13 @@
@Configuration.Orientation
int getRequestedConfigurationOrientation(boolean forDisplay,
@ActivityInfo.ScreenOrientation int requestedOrientation) {
- if (mTransparentPolicy.hasInheritedOrientation()) {
+ if (mAppCompatController.getTransparentPolicy().hasInheritedOrientation()) {
final RootDisplayArea root = getRootDisplayArea();
if (forDisplay && root != null && root.isOrientationDifferentFromDisplay()) {
return reverseConfigurationOrientation(
- mTransparentPolicy.getInheritedOrientation());
+ mAppCompatController.getTransparentPolicy().getInheritedOrientation());
} else {
- return mTransparentPolicy.getInheritedOrientation();
+ return mAppCompatController.getTransparentPolicy().getInheritedOrientation();
}
}
if (task != null && requestedOrientation == SCREEN_ORIENTATION_BEHIND) {
@@ -8187,7 +8188,9 @@
}
void setRequestedOrientation(@ActivityInfo.ScreenOrientation int requestedOrientation) {
- if (mLetterboxUiController.shouldIgnoreRequestedOrientation(requestedOrientation)) {
+ if (mAppCompatController.getAppCompatCapability()
+ .getAppCompatOrientationCapability()
+ .shouldIgnoreRequestedOrientation(requestedOrientation)) {
return;
}
final int originalRelaunchingCount = mPendingRelaunchCount;
@@ -8330,8 +8333,8 @@
@Nullable
CompatDisplayInsets getCompatDisplayInsets() {
- if (mTransparentPolicy.isRunning()) {
- return mTransparentPolicy.getInheritedCompatDisplayInsets();
+ if (mAppCompatController.getTransparentPolicy().isRunning()) {
+ return mAppCompatController.getTransparentPolicy().getInheritedCompatDisplayInsets();
}
return mCompatDisplayInsets;
}
@@ -8494,7 +8497,7 @@
}
mSizeCompatBounds = null;
mCompatDisplayInsets = null;
- mTransparentPolicy.clearInheritedCompatDisplayInsets();
+ mAppCompatController.getTransparentPolicy().clearInheritedCompatDisplayInsets();
}
@VisibleForTesting
@@ -8681,7 +8684,7 @@
}
@Nullable Rect getParentAppBoundsOverride() {
- return Rect.copyOrNull(mResolveConfigHint.mTmpParentAppBoundsOverride);
+ return Rect.copyOrNull(mResolveConfigHint.mParentAppBoundsOverride);
}
/**
@@ -8827,8 +8830,8 @@
return APP_COMPAT_STATE_CHANGED__STATE__NOT_VISIBLE;
}
// TODO(b/256564921): Investigate if we need new metrics for translucent activities
- if (mTransparentPolicy.isRunning()) {
- return mTransparentPolicy.getInheritedAppCompatState();
+ if (mAppCompatController.getTransparentPolicy().isRunning()) {
+ return mAppCompatController.getTransparentPolicy().getInheritedAppCompatState();
}
if (mInSizeCompatModeForBounds) {
return APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_SIZE_COMPAT_MODE;
@@ -8866,7 +8869,7 @@
}
final Rect screenResolvedBounds =
mSizeCompatBounds != null ? mSizeCompatBounds : resolvedBounds;
- final Rect parentAppBounds = mResolveConfigHint.mTmpParentAppBoundsOverride;
+ final Rect parentAppBounds = mResolveConfigHint.mParentAppBoundsOverride;
final Rect parentBounds = newParentConfiguration.windowConfiguration.getBounds();
final float screenResolvedBoundsWidth = screenResolvedBounds.width();
final float parentAppBoundsWidth = parentAppBounds.width();
@@ -8981,7 +8984,7 @@
// We check if the current activity is transparent. In that case we need to
// recomputeConfiguration of the first opaque activity beneath, to allow a
// proper computation of the new bounds.
- if (!mTransparentPolicy.applyOnOpaqueActivityBelow(
+ if (!mAppCompatController.getTransparentPolicy().applyOnOpaqueActivityBelow(
ActivityRecord::recomputeConfiguration)) {
onRequestedOverrideConfigurationChanged(getRequestedOverrideConfiguration());
}
@@ -9275,7 +9278,7 @@
*/
private void resolveAspectRatioRestriction(Configuration newParentConfiguration) {
final Configuration resolvedConfig = getResolvedOverrideConfiguration();
- final Rect parentAppBounds = mResolveConfigHint.mTmpParentAppBoundsOverride;
+ final Rect parentAppBounds = mResolveConfigHint.mParentAppBoundsOverride;
final Rect parentBounds = newParentConfiguration.windowConfiguration.getBounds();
final Rect resolvedBounds = resolvedConfig.windowConfiguration.getBounds();
// Use tmp bounds to calculate aspect ratio so we can know whether the activity should use
@@ -9316,7 +9319,7 @@
: newParentConfiguration.windowConfiguration.getBounds();
final Rect containerAppBounds = useResolvedBounds
? new Rect(resolvedConfig.windowConfiguration.getAppBounds())
- : mResolveConfigHint.mTmpParentAppBoundsOverride;
+ : mResolveConfigHint.mParentAppBoundsOverride;
final int requestedOrientation = getRequestedConfigurationOrientation();
final boolean orientationRequested = requestedOrientation != ORIENTATION_UNDEFINED;
@@ -9441,7 +9444,8 @@
void updateSizeCompatScale(Rect resolvedAppBounds, Rect containerAppBounds) {
// Only allow to scale down.
- mSizeCompatScale = mTransparentPolicy.findOpaqueNotFinishingActivityBelow()
+ mSizeCompatScale = mAppCompatController.getTransparentPolicy()
+ .findOpaqueNotFinishingActivityBelow()
.map(activityRecord -> activityRecord.mSizeCompatScale)
.orElseGet(() -> {
final int contentW = resolvedAppBounds.width();
@@ -9454,7 +9458,7 @@
}
private boolean isInSizeCompatModeForBounds(final Rect appBounds, final Rect containerBounds) {
- if (mTransparentPolicy.isRunning()) {
+ if (mAppCompatController.getTransparentPolicy().isRunning()) {
// To avoid wrong app behaviour, we decided to disable SCM when a translucent activity
// is letterboxed.
return false;
@@ -9517,7 +9521,7 @@
public Rect getBounds() {
// TODO(b/268458693): Refactor configuration inheritance in case of translucent activities
final Rect superBounds = super.getBounds();
- return mTransparentPolicy.findOpaqueNotFinishingActivityBelow()
+ return mAppCompatController.getTransparentPolicy().findOpaqueNotFinishingActivityBelow()
.map(ActivityRecord::getBounds)
.orElseGet(() -> {
if (mSizeCompatBounds != null) {
@@ -9881,8 +9885,8 @@
* Returns the min aspect ratio of this activity.
*/
float getMinAspectRatio() {
- if (mTransparentPolicy.isRunning()) {
- return mTransparentPolicy.getInheritedMinAspectRatio();
+ if (mAppCompatController.getTransparentPolicy().isRunning()) {
+ return mAppCompatController.getTransparentPolicy().getInheritedMinAspectRatio();
}
if (info.applicationInfo == null) {
return info.getMinAspectRatio();
@@ -9932,8 +9936,8 @@
}
float getMaxAspectRatio() {
- if (mTransparentPolicy.isRunning()) {
- return mTransparentPolicy.getInheritedMaxAspectRatio();
+ if (mAppCompatController.getTransparentPolicy().isRunning()) {
+ return mAppCompatController.getTransparentPolicy().getInheritedMaxAspectRatio();
}
return info.getMaxAspectRatio();
}
diff --git a/services/core/java/com/android/server/wm/AppCompatCapability.java b/services/core/java/com/android/server/wm/AppCompatCapability.java
new file mode 100644
index 0000000..d4379e48
--- /dev/null
+++ b/services/core/java/com/android/server/wm/AppCompatCapability.java
@@ -0,0 +1,416 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import static android.content.pm.ActivityInfo.FORCE_NON_RESIZE_APP;
+import static android.content.pm.ActivityInfo.FORCE_RESIZE_APP;
+import static android.content.pm.ActivityInfo.OVERRIDE_ANY_ORIENTATION_TO_USER;
+import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_FORCE_ROTATION;
+import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_FREEFORM_WINDOWING_TREATMENT;
+import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_REFRESH;
+import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE;
+import static android.content.pm.ActivityInfo.OVERRIDE_ENABLE_COMPAT_FAKE_FOCUS;
+import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO;
+import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_ONLY_FOR_CAMERA;
+import static android.content.pm.ActivityInfo.OVERRIDE_ORIENTATION_ONLY_FOR_CAMERA;
+import static android.content.pm.ActivityInfo.OVERRIDE_RESPECT_REQUESTED_ORIENTATION;
+import static android.content.pm.ActivityInfo.OVERRIDE_USE_DISPLAY_LANDSCAPE_NATURAL_ORIENTATION;
+import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_FULLSCREEN;
+import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_UNSET;
+import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
+import static android.view.WindowManager.PROPERTY_CAMERA_COMPAT_ALLOW_FORCE_ROTATION;
+import static android.view.WindowManager.PROPERTY_CAMERA_COMPAT_ALLOW_REFRESH;
+import static android.view.WindowManager.PROPERTY_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE;
+import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_DISPLAY_ORIENTATION_OVERRIDE;
+import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_MIN_ASPECT_RATIO_OVERRIDE;
+import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_ORIENTATION_OVERRIDE;
+import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_RESIZEABLE_ACTIVITY_OVERRIDES;
+import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_FULLSCREEN_OVERRIDE;
+import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_OVERRIDE;
+import static android.view.WindowManager.PROPERTY_COMPAT_ENABLE_FAKE_FOCUS;
+
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
+
+import android.annotation.NonNull;
+import android.content.pm.PackageManager;
+
+import com.android.server.wm.utils.OptPropFactory;
+import com.android.window.flags.Flags;
+
+import java.util.function.BooleanSupplier;
+
+/**
+ * Encapsulate logic related to operations guarded by an app override.
+ */
+public class AppCompatCapability {
+
+ private static final String TAG = TAG_WITH_CLASS_NAME ? "AppCompatCapability" : TAG_ATM;
+
+ @NonNull
+ private final LetterboxConfiguration mLetterboxConfiguration;
+
+ @NonNull
+ private final ActivityRecord mActivityRecord;
+
+ // Corresponds to OVERRIDE_ANY_ORIENTATION_TO_USER
+ private final boolean mIsSystemOverrideToFullscreenEnabled;
+ // Corresponds to OVERRIDE_RESPECT_REQUESTED_ORIENTATION
+ private final boolean mIsOverrideRespectRequestedOrientationEnabled;
+ // Corresponds to OVERRIDE_ORIENTATION_ONLY_FOR_CAMERA
+ private final boolean mIsOverrideOrientationOnlyForCameraEnabled;
+
+ @NonNull
+ private final OptPropFactory.OptProp mFakeFocusOptProp;
+ @NonNull
+ private final OptPropFactory.OptProp mCameraCompatAllowForceRotationOptProp;
+ @NonNull
+ private final OptPropFactory.OptProp mCameraCompatAllowRefreshOptProp;
+ @NonNull
+ private final OptPropFactory.OptProp mCameraCompatEnableRefreshViaPauseOptProp;
+ @NonNull
+ private final OptPropFactory.OptProp mAllowOrientationOverrideOptProp;
+ @NonNull
+ private final OptPropFactory.OptProp mAllowDisplayOrientationOverrideOptProp;
+ @NonNull
+ private final OptPropFactory.OptProp mAllowMinAspectRatioOverrideOptProp;
+ @NonNull
+ private final OptPropFactory.OptProp mAllowForceResizeOverrideOptProp;
+ @NonNull
+ private final OptPropFactory.OptProp mAllowUserAspectRatioOverrideOptProp;
+ @NonNull
+ private final OptPropFactory.OptProp mAllowUserAspectRatioFullscreenOverrideOptProp;
+
+ private final AppCompatOrientationCapability mAppCompatOrientationCapability;
+
+ AppCompatCapability(@NonNull WindowManagerService wmService,
+ @NonNull ActivityRecord activityRecord,
+ @NonNull LetterboxConfiguration letterboxConfiguration) {
+ mLetterboxConfiguration = letterboxConfiguration;
+ mActivityRecord = activityRecord;
+ final PackageManager packageManager = wmService.mContext.getPackageManager();
+
+ final OptPropFactory optPropBuilder = new OptPropFactory(packageManager,
+ activityRecord.packageName);
+
+ mAppCompatOrientationCapability =
+ new AppCompatOrientationCapability(optPropBuilder, mLetterboxConfiguration,
+ mActivityRecord);
+
+ mFakeFocusOptProp = optPropBuilder.create(PROPERTY_COMPAT_ENABLE_FAKE_FOCUS,
+ mLetterboxConfiguration::isCompatFakeFocusEnabled);
+
+ final BooleanSupplier isCameraCompatTreatmentEnabled = asLazy(
+ mLetterboxConfiguration::isCameraCompatTreatmentEnabled);
+ mCameraCompatAllowForceRotationOptProp = optPropBuilder.create(
+ PROPERTY_CAMERA_COMPAT_ALLOW_FORCE_ROTATION,
+ isCameraCompatTreatmentEnabled);
+ mCameraCompatAllowRefreshOptProp = optPropBuilder.create(
+ PROPERTY_CAMERA_COMPAT_ALLOW_REFRESH,
+ isCameraCompatTreatmentEnabled);
+ mCameraCompatEnableRefreshViaPauseOptProp = optPropBuilder.create(
+ PROPERTY_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE,
+ isCameraCompatTreatmentEnabled);
+
+ mAllowOrientationOverrideOptProp = optPropBuilder.create(
+ PROPERTY_COMPAT_ALLOW_ORIENTATION_OVERRIDE);
+
+ mAllowDisplayOrientationOverrideOptProp = optPropBuilder.create(
+ PROPERTY_COMPAT_ALLOW_DISPLAY_ORIENTATION_OVERRIDE,
+ () -> mActivityRecord.mDisplayContent != null
+ && mActivityRecord.getTask() != null
+ && mActivityRecord.mDisplayContent.getIgnoreOrientationRequest()
+ && !mActivityRecord.getTask().inMultiWindowMode()
+ && mActivityRecord.mDisplayContent.getNaturalOrientation()
+ == ORIENTATION_LANDSCAPE
+ );
+
+ mAllowMinAspectRatioOverrideOptProp = optPropBuilder.create(
+ PROPERTY_COMPAT_ALLOW_MIN_ASPECT_RATIO_OVERRIDE);
+ mAllowForceResizeOverrideOptProp = optPropBuilder.create(
+ PROPERTY_COMPAT_ALLOW_RESIZEABLE_ACTIVITY_OVERRIDES);
+ mAllowUserAspectRatioOverrideOptProp = optPropBuilder.create(
+ PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_OVERRIDE,
+ mLetterboxConfiguration::isUserAppAspectRatioSettingsEnabled);
+ mAllowUserAspectRatioFullscreenOverrideOptProp = optPropBuilder.create(
+ PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_FULLSCREEN_OVERRIDE,
+ mLetterboxConfiguration::isUserAppAspectRatioFullscreenEnabled);
+
+ mIsSystemOverrideToFullscreenEnabled =
+ isCompatChangeEnabled(OVERRIDE_ANY_ORIENTATION_TO_USER);
+ mIsOverrideRespectRequestedOrientationEnabled =
+ isCompatChangeEnabled(OVERRIDE_RESPECT_REQUESTED_ORIENTATION);
+ mIsOverrideOrientationOnlyForCameraEnabled =
+ isCompatChangeEnabled(OVERRIDE_ORIENTATION_ONLY_FOR_CAMERA);
+ }
+
+ /**
+ * @return {@code true} if the App Compat Camera Policy is active for the current activity.
+ */
+ boolean isCameraCompatTreatmentActive() {
+ final DisplayContent displayContent = mActivityRecord.mDisplayContent;
+ if (displayContent == null) {
+ return false;
+ }
+ return displayContent.mDisplayRotationCompatPolicy != null
+ && displayContent.mDisplayRotationCompatPolicy
+ .isTreatmentEnabledForActivity(mActivityRecord);
+ }
+
+ @NonNull
+ AppCompatOrientationCapability getAppCompatOrientationCapability() {
+ return mAppCompatOrientationCapability;
+ }
+
+ /**
+ * Whether sending compat fake focus for split screen resumed activities is enabled. Needed
+ * because some game engines wait to get focus before drawing the content of the app which isn't
+ * guaranteed by default in multi-window modes.
+ *
+ * <p>This treatment is enabled when the following conditions are met:
+ * <ul>
+ * <li>Flag gating the treatment is enabled
+ * <li>Component property is NOT set to false
+ * <li>Component property is set to true or per-app override is enabled
+ * </ul>
+ */
+ boolean shouldSendFakeFocus() {
+ return mFakeFocusOptProp.shouldEnableWithOverrideAndProperty(
+ isCompatChangeEnabled(OVERRIDE_ENABLE_COMPAT_FAKE_FOCUS));
+ }
+
+ /**
+ * Whether activity is eligible for camera compat force rotation treatment. See {@link
+ * DisplayRotationCompatPolicy} for context.
+ *
+ * <p>This treatment is enabled when the following conditions are met:
+ * <ul>
+ * <li>Flag gating the camera compat treatment is enabled.
+ * <li>Activity isn't opted out by the device manufacturer with override or by the app
+ * developers with the component property.
+ * </ul>
+ */
+ boolean shouldForceRotateForCameraCompat() {
+ return mCameraCompatAllowForceRotationOptProp.shouldEnableWithOptOutOverrideAndProperty(
+ isCompatChangeEnabled(OVERRIDE_CAMERA_COMPAT_DISABLE_FORCE_ROTATION));
+ }
+
+ /**
+ * Whether activity is eligible for activity "refresh" after camera compat force rotation
+ * treatment. See {@link DisplayRotationCompatPolicy} for context.
+ *
+ * <p>This treatment is enabled when the following conditions are met:
+ * <ul>
+ * <li>Flag gating the camera compat treatment is enabled.
+ * <li>Activity isn't opted out by the device manufacturer with override or by the app
+ * developers with the component property.
+ * </ul>
+ */
+ boolean shouldRefreshActivityForCameraCompat() {
+ return mCameraCompatAllowRefreshOptProp.shouldEnableWithOptOutOverrideAndProperty(
+ isCompatChangeEnabled(OVERRIDE_CAMERA_COMPAT_DISABLE_REFRESH));
+ }
+
+ /**
+ * Whether activity should be "refreshed" after the camera compat force rotation treatment
+ * using the "resumed -> paused -> resumed" cycle rather than the "resumed -> ... -> stopped
+ * -> ... -> resumed" cycle. See {@link DisplayRotationCompatPolicy} for context.
+ *
+ * <p>This treatment is enabled when the following conditions are met:
+ * <ul>
+ * <li>Flag gating the camera compat treatment is enabled.
+ * <li>Activity "refresh" via "resumed -> paused -> resumed" cycle isn't disabled with the
+ * component property by the app developers.
+ * <li>Activity "refresh" via "resumed -> paused -> resumed" cycle is enabled by the device
+ * manufacturer with override / by the app developers with the component property.
+ * </ul>
+ */
+ boolean shouldRefreshActivityViaPauseForCameraCompat() {
+ return mCameraCompatEnableRefreshViaPauseOptProp.shouldEnableWithOverrideAndProperty(
+ isCompatChangeEnabled(OVERRIDE_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE));
+ }
+
+ boolean isSystemOverrideToFullscreenEnabled(int userAspectRatio) {
+ return mIsSystemOverrideToFullscreenEnabled
+ && !mAllowOrientationOverrideOptProp.isFalse()
+ && (userAspectRatio == USER_MIN_ASPECT_RATIO_UNSET
+ || userAspectRatio == USER_MIN_ASPECT_RATIO_FULLSCREEN);
+ }
+
+ boolean isAllowOrientationOverrideOptOut() {
+ return mAllowOrientationOverrideOptProp.isFalse();
+ }
+
+ /**
+ * Whether we should apply the min aspect ratio per-app override. When this override is applied
+ * the min aspect ratio given in the app's manifest will be overridden to the largest enabled
+ * aspect ratio treatment unless the app's manifest value is higher. The treatment will also
+ * apply if no value is provided in the manifest.
+ *
+ * <p>This method returns {@code true} when the following conditions are met:
+ * <ul>
+ * <li>Opt-out component property isn't enabled
+ * <li>Per-app override is enabled
+ * </ul>
+ */
+ boolean shouldOverrideMinAspectRatio() {
+ return mAllowMinAspectRatioOverrideOptProp.shouldEnableWithOptInOverrideAndOptOutProperty(
+ isCompatChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO));
+ }
+
+ boolean isOverrideRespectRequestedOrientationEnabled() {
+ return mIsOverrideRespectRequestedOrientationEnabled;
+ }
+
+ boolean isOverrideOrientationOnlyForCameraEnabled() {
+ return mIsOverrideOrientationOnlyForCameraEnabled;
+ }
+
+ /**
+ * Whether activity is eligible for camera compatibility free-form treatment.
+ *
+ * <p>The treatment is applied to a fixed-orientation camera activity in free-form windowing
+ * mode. The treatment letterboxes or pillarboxes the activity to the expected orientation and
+ * provides changes to the camera and display orientation signals to match those expected on a
+ * portrait device in that orientation (for example, on a standard phone).
+ *
+ * <p>The treatment is enabled when the following conditions are met:
+ * <ul>
+ * <li>Property gating the camera compatibility free-form treatment is enabled.
+ * <li>Activity isn't opted out by the device manufacturer with override.
+ * </ul>
+ */
+ boolean shouldApplyFreeformTreatmentForCameraCompat() {
+ return Flags.cameraCompatForFreeform() && !isCompatChangeEnabled(
+ OVERRIDE_CAMERA_COMPAT_DISABLE_FREEFORM_WINDOWING_TREATMENT);
+ }
+
+
+ /**
+ * Whether we should apply the min aspect ratio per-app override only when an app is connected
+ * to the camera.
+ * When this override is applied the min aspect ratio given in the app's manifest will be
+ * overridden to the largest enabled aspect ratio treatment unless the app's manifest value
+ * is higher. The treatment will also apply if no value is provided in the manifest.
+ *
+ * <p>This method returns {@code true} when the following conditions are met:
+ * <ul>
+ * <li>Opt-out component property isn't enabled
+ * <li>Per-app override is enabled
+ * </ul>
+ */
+ boolean shouldOverrideMinAspectRatioForCamera() {
+ return mActivityRecord.isCameraActive()
+ && mAllowMinAspectRatioOverrideOptProp
+ .shouldEnableWithOptInOverrideAndOptOutProperty(
+ isCompatChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO_ONLY_FOR_CAMERA));
+ }
+
+ /**
+ * Whether should fix display orientation to landscape natural orientation when a task is
+ * fullscreen and the display is ignoring orientation requests.
+ *
+ * <p>This treatment is enabled when the following conditions are met:
+ * <ul>
+ * <li>Opt-out component property isn't enabled
+ * <li>Opt-in per-app override is enabled
+ * <li>Task is in fullscreen.
+ * <li>{@link DisplayContent#getIgnoreOrientationRequest} is enabled
+ * <li>Natural orientation of the display is landscape.
+ * </ul>
+ */
+ boolean shouldUseDisplayLandscapeNaturalOrientation() {
+ return mAllowDisplayOrientationOverrideOptProp
+ .shouldEnableWithOptInOverrideAndOptOutProperty(
+ isCompatChangeEnabled(OVERRIDE_USE_DISPLAY_LANDSCAPE_NATURAL_ORIENTATION));
+ }
+
+ /**
+ * Whether we should apply the force resize per-app override. When this override is applied it
+ * forces the packages it is applied to to be resizable. It won't change whether the app can be
+ * put into multi-windowing mode, but allow the app to resize without going into size-compat
+ * mode when the window container resizes, such as display size change or screen rotation.
+ *
+ * <p>This method returns {@code true} when the following conditions are met:
+ * <ul>
+ * <li>Opt-out component property isn't enabled
+ * <li>Per-app override is enabled
+ * </ul>
+ */
+ boolean shouldOverrideForceResizeApp() {
+ return mAllowForceResizeOverrideOptProp.shouldEnableWithOptInOverrideAndOptOutProperty(
+ isCompatChangeEnabled(FORCE_RESIZE_APP));
+ }
+
+ /**
+ * Whether we should enable users to resize the current app.
+ */
+ boolean shouldEnableUserAspectRatioSettings() {
+ // We use mBooleanPropertyAllowUserAspectRatioOverride to allow apps to opt-out which has
+ // effect only if explicitly false. If mBooleanPropertyAllowUserAspectRatioOverride is null,
+ // the current app doesn't opt-out so the first part of the predicate is true.
+ return !mAllowUserAspectRatioOverrideOptProp.isFalse()
+ && mLetterboxConfiguration.isUserAppAspectRatioSettingsEnabled()
+ && mActivityRecord.mDisplayContent != null
+ && mActivityRecord.mDisplayContent.getIgnoreOrientationRequest();
+ }
+
+ boolean isUserFullscreenOverrideEnabled() {
+ if (mAllowUserAspectRatioOverrideOptProp.isFalse()
+ || mAllowUserAspectRatioFullscreenOverrideOptProp.isFalse()
+ || !mLetterboxConfiguration.isUserAppAspectRatioFullscreenEnabled()) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Whether we should apply the force non resize per-app override. When this override is applied
+ * it forces the packages it is applied to to be non-resizable.
+ *
+ * <p>This method returns {@code true} when the following conditions are met:
+ * <ul>
+ * <li>Opt-out component property isn't enabled
+ * <li>Per-app override is enabled
+ * </ul>
+ */
+ boolean shouldOverrideForceNonResizeApp() {
+ return mAllowForceResizeOverrideOptProp.shouldEnableWithOptInOverrideAndOptOutProperty(
+ isCompatChangeEnabled(FORCE_NON_RESIZE_APP));
+ }
+
+ private boolean isCompatChangeEnabled(long overrideChangeId) {
+ return mActivityRecord.info.isChangeEnabled(overrideChangeId);
+ }
+
+ @NonNull
+ static BooleanSupplier asLazy(@NonNull BooleanSupplier supplier) {
+ return new BooleanSupplier() {
+ private boolean mRead;
+ private boolean mValue;
+
+ @Override
+ public boolean getAsBoolean() {
+ if (!mRead) {
+ mRead = true;
+ mValue = supplier.getAsBoolean();
+ }
+ return mValue;
+ }
+ };
+ }
+}
diff --git a/services/core/java/com/android/server/wm/AppCompatController.java b/services/core/java/com/android/server/wm/AppCompatController.java
new file mode 100644
index 0000000..3ff0fce
--- /dev/null
+++ b/services/core/java/com/android/server/wm/AppCompatController.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.wm;
+
+import android.annotation.NonNull;
+
+/**
+ * Allows the interaction with all the app compat policies and configurations
+ */
+class AppCompatController {
+
+ @NonNull
+ private final TransparentPolicy mTransparentPolicy;
+ @NonNull
+ private final AppCompatOrientationPolicy mOrientationPolicy;
+ @NonNull
+ private final AppCompatCapability mAppCompatCapability;
+
+ AppCompatController(@NonNull WindowManagerService wmService,
+ @NonNull ActivityRecord activityRecord) {
+ mTransparentPolicy = new TransparentPolicy(activityRecord,
+ wmService.mLetterboxConfiguration);
+ mAppCompatCapability = new AppCompatCapability(wmService, activityRecord,
+ wmService.mLetterboxConfiguration);
+ // TODO(b/341903757) Remove BooleanSuppliers after fixing dependency with aspectRatio.
+ final LetterboxUiController tmpController = activityRecord.mLetterboxUiController;
+ mOrientationPolicy = new AppCompatOrientationPolicy(activityRecord,
+ mAppCompatCapability, tmpController::shouldApplyUserFullscreenOverride,
+ tmpController::shouldApplyUserMinAspectRatioOverride,
+ tmpController::isSystemOverrideToFullscreenEnabled);
+ }
+
+ @NonNull
+ TransparentPolicy getTransparentPolicy() {
+ return mTransparentPolicy;
+ }
+
+ @NonNull
+ AppCompatOrientationPolicy getOrientationPolicy() {
+ return mOrientationPolicy;
+ }
+
+ @NonNull
+ AppCompatCapability getAppCompatCapability() {
+ return mAppCompatCapability;
+ }
+}
diff --git a/services/core/java/com/android/server/wm/AppCompatOrientationCapability.java b/services/core/java/com/android/server/wm/AppCompatOrientationCapability.java
new file mode 100644
index 0000000..fbe90a2
--- /dev/null
+++ b/services/core/java/com/android/server/wm/AppCompatOrientationCapability.java
@@ -0,0 +1,251 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import static android.content.pm.ActivityInfo.OVERRIDE_ANY_ORIENTATION;
+import static android.content.pm.ActivityInfo.OVERRIDE_ENABLE_COMPAT_IGNORE_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED;
+import static android.content.pm.ActivityInfo.OVERRIDE_ENABLE_COMPAT_IGNORE_REQUESTED_ORIENTATION;
+import static android.content.pm.ActivityInfo.OVERRIDE_LANDSCAPE_ORIENTATION_TO_REVERSE_LANDSCAPE;
+import static android.content.pm.ActivityInfo.OVERRIDE_UNDEFINED_ORIENTATION_TO_NOSENSOR;
+import static android.content.pm.ActivityInfo.OVERRIDE_UNDEFINED_ORIENTATION_TO_PORTRAIT;
+import static android.content.pm.ActivityInfo.screenOrientationToString;
+import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_IGNORING_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED;
+import static android.view.WindowManager.PROPERTY_COMPAT_IGNORE_REQUESTED_ORIENTATION;
+
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.wm.AppCompatCapability.asLazy;
+
+import android.annotation.NonNull;
+import android.content.pm.ActivityInfo;
+import android.util.Slog;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.wm.utils.OptPropFactory;
+
+import java.util.function.BooleanSupplier;
+
+class AppCompatOrientationCapability {
+
+ private static final String TAG = TAG_WITH_CLASS_NAME ? "AppCompatCapability" : TAG_ATM;
+
+ @NonNull
+ private final ActivityRecord mActivityRecord;
+
+ @NonNull
+ private final OptPropFactory.OptProp mIgnoreRequestedOrientationOptProp;
+ @NonNull
+ private final OptPropFactory.OptProp mAllowIgnoringOrientationRequestWhenLoopDetectedOptProp;
+
+ @NonNull
+ final OrientationCapabilityState mOrientationCapabilityState;
+
+ AppCompatOrientationCapability(@NonNull OptPropFactory optPropBuilder,
+ @NonNull LetterboxConfiguration letterboxConfiguration,
+ @NonNull ActivityRecord activityRecord) {
+ mActivityRecord = activityRecord;
+ mOrientationCapabilityState = new OrientationCapabilityState(mActivityRecord);
+ final BooleanSupplier isPolicyForIgnoringRequestedOrientationEnabled = asLazy(
+ letterboxConfiguration::isPolicyForIgnoringRequestedOrientationEnabled);
+ mIgnoreRequestedOrientationOptProp = optPropBuilder.create(
+ PROPERTY_COMPAT_IGNORE_REQUESTED_ORIENTATION,
+ isPolicyForIgnoringRequestedOrientationEnabled);
+ mAllowIgnoringOrientationRequestWhenLoopDetectedOptProp = optPropBuilder.create(
+ PROPERTY_COMPAT_ALLOW_IGNORING_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED,
+ isPolicyForIgnoringRequestedOrientationEnabled);
+ }
+
+ /**
+ * Whether should ignore app requested orientation in response to an app
+ * calling {@link android.app.Activity#setRequestedOrientation}.
+ *
+ * <p>This is needed to avoid getting into {@link android.app.Activity#setRequestedOrientation}
+ * loop when {@link DisplayContent#getIgnoreOrientationRequest} is enabled or device has
+ * landscape natural orientation which app developers don't expect. For example, the loop can
+ * look like this:
+ * <ol>
+ * <li>App sets default orientation to "unspecified" at runtime
+ * <li>App requests to "portrait" after checking some condition (e.g. display rotation).
+ * <li>(2) leads to fullscreen -> letterboxed bounds change and activity relaunch because
+ * app can't handle the corresponding config changes.
+ * <li>Loop goes back to (1)
+ * </ol>
+ *
+ * <p>This treatment is enabled when the following conditions are met:
+ * <ul>
+ * <li>Flag gating the treatment is enabled
+ * <li>Opt-out component property isn't enabled
+ * <li>Opt-in component property or per-app override are enabled
+ * <li>Activity is relaunched after {@link android.app.Activity#setRequestedOrientation}
+ * call from an app or camera compat force rotation treatment is active for the activity.
+ * <li>Orientation request loop detected and is not letterboxed for fixed orientation
+ * </ul>
+ */
+ boolean shouldIgnoreRequestedOrientation(
+ @ActivityInfo.ScreenOrientation int requestedOrientation) {
+ if (mIgnoreRequestedOrientationOptProp.shouldEnableWithOverrideAndProperty(
+ isCompatChangeEnabled(OVERRIDE_ENABLE_COMPAT_IGNORE_REQUESTED_ORIENTATION))) {
+ if (mOrientationCapabilityState.mIsRelaunchingAfterRequestedOrientationChanged) {
+ Slog.w(TAG, "Ignoring orientation update to "
+ + screenOrientationToString(requestedOrientation)
+ + " due to relaunching after setRequestedOrientation for "
+ + mActivityRecord);
+ return true;
+ }
+ if (isCameraCompatTreatmentActive()) {
+ Slog.w(TAG, "Ignoring orientation update to "
+ + screenOrientationToString(requestedOrientation)
+ + " due to camera compat treatment for " + mActivityRecord);
+ return true;
+ }
+ }
+
+ if (shouldIgnoreOrientationRequestLoop()) {
+ Slog.w(TAG, "Ignoring orientation update to "
+ + screenOrientationToString(requestedOrientation)
+ + " as orientation request loop was detected for "
+ + mActivityRecord);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Whether an app is calling {@link android.app.Activity#setRequestedOrientation}
+ * in a loop and orientation request should be ignored.
+ *
+ * <p>This should only be called once in response to
+ * {@link android.app.Activity#setRequestedOrientation}. See
+ * {@link #shouldIgnoreRequestedOrientation} for more details.
+ *
+ * <p>This treatment is enabled when the following conditions are met:
+ * <ul>
+ * <li>Flag gating the treatment is enabled
+ * <li>Opt-out component property isn't enabled
+ * <li>Per-app override is enabled
+ * <li>App has requested orientation more than 2 times within 1-second
+ * timer and activity is not letterboxed for fixed orientation
+ * </ul>
+ */
+ boolean shouldIgnoreOrientationRequestLoop() {
+ final boolean loopDetectionEnabled = isCompatChangeEnabled(
+ OVERRIDE_ENABLE_COMPAT_IGNORE_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED);
+ if (!mAllowIgnoringOrientationRequestWhenLoopDetectedOptProp
+ .shouldEnableWithOptInOverrideAndOptOutProperty(loopDetectionEnabled)) {
+ return false;
+ }
+ mOrientationCapabilityState.updateOrientationRequestLoopState();
+
+ return mOrientationCapabilityState.shouldIgnoreRequestInLoop()
+ && !mActivityRecord.isLetterboxedForFixedOrientationAndAspectRatio();
+ }
+
+ /**
+ * Sets whether an activity is relaunching after the app has called {@link
+ * android.app.Activity#setRequestedOrientation}.
+ */
+ void setRelaunchingAfterRequestedOrientationChanged(boolean isRelaunching) {
+ mOrientationCapabilityState
+ .mIsRelaunchingAfterRequestedOrientationChanged = isRelaunching;
+ }
+
+ boolean getIsRelaunchingAfterRequestedOrientationChanged() {
+ return mOrientationCapabilityState.mIsRelaunchingAfterRequestedOrientationChanged;
+ }
+
+ @VisibleForTesting
+ int getSetOrientationRequestCounter() {
+ return mOrientationCapabilityState.mSetOrientationRequestCounter;
+ }
+
+ private boolean isCompatChangeEnabled(long overrideChangeId) {
+ return mActivityRecord.info.isChangeEnabled(overrideChangeId);
+ }
+
+ /**
+ * @return {@code true} if the App Compat Camera Policy is active for the current activity.
+ */
+ // TODO(b/346253439): Remove after defining dependency with Camera capabilities.
+ private boolean isCameraCompatTreatmentActive() {
+ DisplayContent displayContent = mActivityRecord.mDisplayContent;
+ if (displayContent == null) {
+ return false;
+ }
+ return displayContent.mDisplayRotationCompatPolicy != null
+ && displayContent.mDisplayRotationCompatPolicy
+ .isTreatmentEnabledForActivity(mActivityRecord);
+ }
+
+ static class OrientationCapabilityState {
+ // Corresponds to OVERRIDE_UNDEFINED_ORIENTATION_TO_NOSENSOR
+ final boolean mIsOverrideToNosensorOrientationEnabled;
+ // Corresponds to OVERRIDE_UNDEFINED_ORIENTATION_TO_PORTRAIT
+ final boolean mIsOverrideToPortraitOrientationEnabled;
+ // Corresponds to OVERRIDE_ANY_ORIENTATION
+ final boolean mIsOverrideAnyOrientationEnabled;
+ // Corresponds to OVERRIDE_LANDSCAPE_ORIENTATION_TO_REVERSE_LANDSCAPE
+ final boolean mIsOverrideToReverseLandscapeOrientationEnabled;
+
+ private boolean mIsRelaunchingAfterRequestedOrientationChanged;
+
+ // Used to determine reset of mSetOrientationRequestCounter if next app requested
+ // orientation is after timeout value
+ @VisibleForTesting
+ static final int SET_ORIENTATION_REQUEST_COUNTER_TIMEOUT_MS = 1000;
+ // Minimum value of mSetOrientationRequestCounter before qualifying as orientation request
+ // loop
+ @VisibleForTesting
+ static final int MIN_COUNT_TO_IGNORE_REQUEST_IN_LOOP = 2;
+ // Updated when ActivityRecord#setRequestedOrientation is called
+ private long mTimeMsLastSetOrientationRequest = 0;
+ // Counter for ActivityRecord#setRequestedOrientation
+ private int mSetOrientationRequestCounter = 0;
+
+ OrientationCapabilityState(@NonNull ActivityRecord activityRecord) {
+ mIsOverrideToNosensorOrientationEnabled =
+ activityRecord.info.isChangeEnabled(OVERRIDE_UNDEFINED_ORIENTATION_TO_NOSENSOR);
+ mIsOverrideToPortraitOrientationEnabled =
+ activityRecord.info.isChangeEnabled(OVERRIDE_UNDEFINED_ORIENTATION_TO_PORTRAIT);
+ mIsOverrideAnyOrientationEnabled =
+ activityRecord.info.isChangeEnabled(OVERRIDE_ANY_ORIENTATION);
+ mIsOverrideToReverseLandscapeOrientationEnabled = activityRecord.info
+ .isChangeEnabled(OVERRIDE_LANDSCAPE_ORIENTATION_TO_REVERSE_LANDSCAPE);
+ }
+
+ /**
+ * @return {@code true} if we should start ignoring orientation in a orientation request
+ * loop.
+ */
+ boolean shouldIgnoreRequestInLoop() {
+ return mSetOrientationRequestCounter >= MIN_COUNT_TO_IGNORE_REQUEST_IN_LOOP;
+ }
+
+ /**
+ * Updates the orientation request counter using a specific timeout.
+ */
+ void updateOrientationRequestLoopState() {
+ final long currTimeMs = System.currentTimeMillis();
+ final long elapsedTime = currTimeMs - mTimeMsLastSetOrientationRequest;
+ if (elapsedTime < SET_ORIENTATION_REQUEST_COUNTER_TIMEOUT_MS) {
+ mSetOrientationRequestCounter++;
+ } else {
+ mSetOrientationRequestCounter = 0;
+ }
+ mTimeMsLastSetOrientationRequest = currTimeMs;
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/wm/AppCompatOrientationPolicy.java b/services/core/java/com/android/server/wm/AppCompatOrientationPolicy.java
new file mode 100644
index 0000000..c505ff9
--- /dev/null
+++ b/services/core/java/com/android/server/wm/AppCompatOrientationPolicy.java
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LOCKED;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_USER;
+import static android.content.pm.ActivityInfo.isFixedOrientation;
+import static android.content.pm.ActivityInfo.isFixedOrientationLandscape;
+import static android.content.pm.ActivityInfo.screenOrientationToString;
+
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
+
+import android.annotation.NonNull;
+import android.content.pm.ActivityInfo;
+import android.util.Slog;
+
+import java.util.function.BooleanSupplier;
+
+/**
+ * Contains all the logic related to orientation in the context of app compatibility
+ */
+class AppCompatOrientationPolicy {
+
+ private static final String TAG = TAG_WITH_CLASS_NAME ? "AppCompatOrientationPolicy" : TAG_ATM;
+
+ @NonNull
+ private final ActivityRecord mActivityRecord;
+
+ @NonNull
+ private final AppCompatCapability mAppCompatCapability;
+
+ @NonNull
+ private final BooleanSupplier mShouldApplyUserFullscreenOverride;
+ @NonNull
+ private final BooleanSupplier mShouldApplyUserMinAspectRatioOverride;
+ @NonNull
+ private final BooleanSupplier mIsSystemOverrideToFullscreenEnabled;
+
+ // TODO(b/341903757) Remove BooleanSuppliers after fixing dependency with spectRatio component
+ AppCompatOrientationPolicy(@NonNull ActivityRecord activityRecord,
+ @NonNull AppCompatCapability appCompatCapability,
+ @NonNull BooleanSupplier shouldApplyUserFullscreenOverride,
+ @NonNull BooleanSupplier shouldApplyUserMinAspectRatioOverride,
+ @NonNull BooleanSupplier isSystemOverrideToFullscreenEnabled) {
+ mActivityRecord = activityRecord;
+ mAppCompatCapability = appCompatCapability;
+ mShouldApplyUserFullscreenOverride = shouldApplyUserFullscreenOverride;
+ mShouldApplyUserMinAspectRatioOverride = shouldApplyUserMinAspectRatioOverride;
+ mIsSystemOverrideToFullscreenEnabled = isSystemOverrideToFullscreenEnabled;
+ }
+
+ @ActivityInfo.ScreenOrientation
+ int overrideOrientationIfNeeded(@ActivityInfo.ScreenOrientation int candidate) {
+ final DisplayContent displayContent = mActivityRecord.mDisplayContent;
+ final boolean isIgnoreOrientationRequestEnabled = displayContent != null
+ && displayContent.getIgnoreOrientationRequest();
+ if (mShouldApplyUserFullscreenOverride.getAsBoolean() && isIgnoreOrientationRequestEnabled
+ // Do not override orientation to fullscreen for camera activities.
+ // Fixed-orientation activities are rarely tested in other orientations, and it
+ // often results in sideways or stretched previews. As the camera compat treatment
+ // targets fixed-orientation activities, overriding the orientation disables the
+ // treatment.
+ && !mActivityRecord.isCameraActive()) {
+ Slog.v(TAG, "Requested orientation " + screenOrientationToString(candidate)
+ + " for " + mActivityRecord + " is overridden to "
+ + screenOrientationToString(SCREEN_ORIENTATION_USER)
+ + " by user aspect ratio settings.");
+ return SCREEN_ORIENTATION_USER;
+ }
+
+ // In some cases (e.g. Kids app) we need to map the candidate orientation to some other
+ // orientation.
+ candidate = mActivityRecord.mWmService.mapOrientationRequest(candidate);
+
+ if (mShouldApplyUserMinAspectRatioOverride.getAsBoolean() && (!isFixedOrientation(candidate)
+ || candidate == SCREEN_ORIENTATION_LOCKED)) {
+ Slog.v(TAG, "Requested orientation " + screenOrientationToString(candidate)
+ + " for " + mActivityRecord + " is overridden to "
+ + screenOrientationToString(SCREEN_ORIENTATION_PORTRAIT)
+ + " by user aspect ratio settings.");
+ return SCREEN_ORIENTATION_PORTRAIT;
+ }
+
+ if (mAppCompatCapability.isAllowOrientationOverrideOptOut()) {
+ return candidate;
+ }
+
+ if (displayContent != null && mAppCompatCapability
+ .isOverrideOrientationOnlyForCameraEnabled()
+ && (displayContent.mDisplayRotationCompatPolicy == null
+ || !displayContent.mDisplayRotationCompatPolicy
+ .isActivityEligibleForOrientationOverride(mActivityRecord))) {
+ return candidate;
+ }
+
+ // mUserAspectRatio is always initialized first in shouldApplyUserFullscreenOverride(),
+ // which will always come first before this check as user override > device
+ // manufacturer override.
+ if (mIsSystemOverrideToFullscreenEnabled.getAsBoolean() && isIgnoreOrientationRequestEnabled
+ // Do not override orientation to fullscreen for camera activities.
+ // Fixed-orientation activities are rarely tested in other orientations, and it
+ // often results in sideways or stretched previews. As the camera compat treatment
+ // targets fixed-orientation activities, overriding the orientation disables the
+ // treatment.
+ && !mActivityRecord.isCameraActive()) {
+ Slog.v(TAG, "Requested orientation " + screenOrientationToString(candidate)
+ + " for " + mActivityRecord + " is overridden to "
+ + screenOrientationToString(SCREEN_ORIENTATION_USER));
+ return SCREEN_ORIENTATION_USER;
+ }
+
+ final AppCompatOrientationCapability.OrientationCapabilityState capabilityState =
+ mAppCompatCapability.getAppCompatOrientationCapability()
+ .mOrientationCapabilityState;
+
+ if (capabilityState.mIsOverrideToReverseLandscapeOrientationEnabled
+ && (isFixedOrientationLandscape(candidate)
+ || capabilityState.mIsOverrideAnyOrientationEnabled)) {
+ Slog.w(TAG, "Requested orientation " + screenOrientationToString(candidate) + " for "
+ + mActivityRecord + " is overridden to "
+ + screenOrientationToString(SCREEN_ORIENTATION_REVERSE_LANDSCAPE));
+ return SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
+ }
+
+ if (!capabilityState.mIsOverrideAnyOrientationEnabled && isFixedOrientation(candidate)) {
+ return candidate;
+ }
+
+ if (capabilityState.mIsOverrideToPortraitOrientationEnabled) {
+ Slog.w(TAG, "Requested orientation " + screenOrientationToString(candidate) + " for "
+ + mActivityRecord + " is overridden to "
+ + screenOrientationToString(SCREEN_ORIENTATION_PORTRAIT));
+ return SCREEN_ORIENTATION_PORTRAIT;
+ }
+
+ if (capabilityState.mIsOverrideToNosensorOrientationEnabled) {
+ Slog.w(TAG, "Requested orientation " + screenOrientationToString(candidate) + " for "
+ + mActivityRecord + " is overridden to "
+ + screenOrientationToString(SCREEN_ORIENTATION_NOSENSOR));
+ return SCREEN_ORIENTATION_NOSENSOR;
+ }
+
+ return candidate;
+ }
+
+}
diff --git a/services/core/java/com/android/server/wm/BackNavigationController.java b/services/core/java/com/android/server/wm/BackNavigationController.java
index 1ce324f..5699fdd 100644
--- a/services/core/java/com/android/server/wm/BackNavigationController.java
+++ b/services/core/java/com/android/server/wm/BackNavigationController.java
@@ -252,7 +252,8 @@
// skip if one of participant activity is translucent
backType = BackNavigationInfo.TYPE_CALLBACK;
} else if (prevActivities.size() > 0) {
- if (!isOccluded || isAllActivitiesCanShowWhenLocked(prevActivities)) {
+ if ((!isOccluded || isAllActivitiesCanShowWhenLocked(prevActivities))
+ && isAllActivitiesCreated(prevActivities)) {
// We have another Activity in the same currentTask to go to
final WindowContainer parent = currentActivity.getParent();
final boolean canCustomize = parent != null
@@ -549,6 +550,17 @@
return !prevActivities.isEmpty();
}
+ private static boolean isAllActivitiesCreated(
+ @NonNull ArrayList<ActivityRecord> prevActivities) {
+ for (int i = prevActivities.size() - 1; i >= 0; --i) {
+ final ActivityRecord check = prevActivities.get(i);
+ if (check.isState(ActivityRecord.State.INITIALIZING)) {
+ return false;
+ }
+ }
+ return !prevActivities.isEmpty();
+ }
+
boolean isMonitoringTransition() {
return mAnimationHandler.mComposed || mNavigationMonitor.isMonitorForRemote();
}
diff --git a/services/core/java/com/android/server/wm/Letterbox.java b/services/core/java/com/android/server/wm/Letterbox.java
index 362d4ef..2aa7c0c 100644
--- a/services/core/java/com/android/server/wm/Letterbox.java
+++ b/services/core/java/com/android/server/wm/Letterbox.java
@@ -20,6 +20,7 @@
import static android.view.SurfaceControl.HIDDEN;
import static android.window.TaskConstants.TASK_CHILD_LAYER_LETTERBOX_BACKGROUND;
+import android.annotation.NonNull;
import android.graphics.Color;
import android.graphics.Point;
import android.graphics.Rect;
@@ -209,16 +210,18 @@
return false;
}
- public void applySurfaceChanges(SurfaceControl.Transaction t) {
+ /** Applies surface changes such as colour, window crop, position and input info. */
+ public void applySurfaceChanges(@NonNull SurfaceControl.Transaction t,
+ @NonNull SurfaceControl.Transaction inputT) {
if (useFullWindowSurface()) {
- mFullWindowSurface.applySurfaceChanges(t);
+ mFullWindowSurface.applySurfaceChanges(t, inputT);
for (LetterboxSurface surface : mSurfaces) {
surface.remove();
}
} else {
for (LetterboxSurface surface : mSurfaces) {
- surface.applySurfaceChanges(t);
+ surface.applySurfaceChanges(t, inputT);
}
mFullWindowSurface.remove();
@@ -418,7 +421,8 @@
return Math.max(0, mLayoutFrameGlobal.height());
}
- public void applySurfaceChanges(SurfaceControl.Transaction t) {
+ public void applySurfaceChanges(@NonNull SurfaceControl.Transaction t,
+ @NonNull SurfaceControl.Transaction inputT) {
if (!needsApplySurfaceChanges()) {
// Nothing changed.
return;
@@ -446,7 +450,7 @@
}
if (mSurface != null && mInputInterceptor != null) {
mInputInterceptor.updateTouchableRegion(mSurfaceFrameRelative);
- t.setInputWindowInfo(mSurface, mInputInterceptor.mWindowHandle);
+ inputT.setInputWindowInfo(mSurface, mInputInterceptor.mWindowHandle);
}
}
diff --git a/services/core/java/com/android/server/wm/LetterboxUiController.java b/services/core/java/com/android/server/wm/LetterboxUiController.java
index 14a0467..17547f5 100644
--- a/services/core/java/com/android/server/wm/LetterboxUiController.java
+++ b/services/core/java/com/android/server/wm/LetterboxUiController.java
@@ -18,33 +18,7 @@
import static android.app.CameraCompatTaskInfo.CAMERA_COMPAT_FREEFORM_NONE;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
-import static android.content.pm.ActivityInfo.FORCE_NON_RESIZE_APP;
-import static android.content.pm.ActivityInfo.FORCE_RESIZE_APP;
-import static android.content.pm.ActivityInfo.OVERRIDE_ANY_ORIENTATION;
-import static android.content.pm.ActivityInfo.OVERRIDE_ANY_ORIENTATION_TO_USER;
-import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_FORCE_ROTATION;
-import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_FREEFORM_WINDOWING_TREATMENT;
-import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_REFRESH;
-import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE;
-import static android.content.pm.ActivityInfo.OVERRIDE_ENABLE_COMPAT_FAKE_FOCUS;
-import static android.content.pm.ActivityInfo.OVERRIDE_ENABLE_COMPAT_IGNORE_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED;
-import static android.content.pm.ActivityInfo.OVERRIDE_ENABLE_COMPAT_IGNORE_REQUESTED_ORIENTATION;
-import static android.content.pm.ActivityInfo.OVERRIDE_LANDSCAPE_ORIENTATION_TO_REVERSE_LANDSCAPE;
-import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO;
-import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_ONLY_FOR_CAMERA;
-import static android.content.pm.ActivityInfo.OVERRIDE_ORIENTATION_ONLY_FOR_CAMERA;
-import static android.content.pm.ActivityInfo.OVERRIDE_RESPECT_REQUESTED_ORIENTATION;
-import static android.content.pm.ActivityInfo.OVERRIDE_UNDEFINED_ORIENTATION_TO_NOSENSOR;
-import static android.content.pm.ActivityInfo.OVERRIDE_UNDEFINED_ORIENTATION_TO_PORTRAIT;
-import static android.content.pm.ActivityInfo.OVERRIDE_USE_DISPLAY_LANDSCAPE_NATURAL_ORIENTATION;
-import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LOCKED;
-import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
-import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
-import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
-import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_USER;
-import static android.content.pm.ActivityInfo.isFixedOrientation;
import static android.content.pm.ActivityInfo.isFixedOrientationLandscape;
-import static android.content.pm.ActivityInfo.screenOrientationToString;
import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_16_9;
import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_3_2;
import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_4_3;
@@ -53,22 +27,9 @@
import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_FULLSCREEN;
import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_SPLIT_SCREEN;
import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_UNSET;
-import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
-import static android.view.WindowManager.PROPERTY_CAMERA_COMPAT_ALLOW_FORCE_ROTATION;
-import static android.view.WindowManager.PROPERTY_CAMERA_COMPAT_ALLOW_REFRESH;
-import static android.view.WindowManager.PROPERTY_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE;
-import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_DISPLAY_ORIENTATION_OVERRIDE;
-import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_IGNORING_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED;
-import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_MIN_ASPECT_RATIO_OVERRIDE;
-import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_ORIENTATION_OVERRIDE;
-import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_RESIZEABLE_ACTIVITY_OVERRIDES;
-import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_FULLSCREEN_OVERRIDE;
-import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_OVERRIDE;
-import static android.view.WindowManager.PROPERTY_COMPAT_ENABLE_FAKE_FOCUS;
-import static android.view.WindowManager.PROPERTY_COMPAT_IGNORE_REQUESTED_ORIENTATION;
import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__LETTERBOX_POSITION__BOTTOM;
import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__LETTERBOX_POSITION__CENTER;
@@ -126,31 +87,17 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.statusbar.LetterboxDetails;
import com.android.server.wm.LetterboxConfiguration.LetterboxBackgroundType;
-import com.android.server.wm.utils.OptPropFactory;
-import com.android.server.wm.utils.OptPropFactory.OptProp;
import com.android.window.flags.Flags;
import java.io.PrintWriter;
-import java.util.function.BooleanSupplier;
/** Controls behaviour of the letterbox UI for {@link mActivityRecord}. */
// TODO(b/185262487): Improve test coverage of this class. Parts of it are tested in
// SizeCompatTests and LetterboxTests but not all.
-// TODO(b/185264020): Consider making LetterboxUiController applicable to any level of the
-// hierarchy in addition to ActivityRecord (Task, DisplayArea, ...).
-// TODO(b/263021211): Consider renaming to more generic CompatUIController.
final class LetterboxUiController {
private static final String TAG = TAG_WITH_CLASS_NAME ? "LetterboxUiController" : TAG_ATM;
- // Minimum value of mSetOrientationRequestCounter before qualifying as orientation request loop
- @VisibleForTesting
- static final int MIN_COUNT_TO_IGNORE_REQUEST_IN_LOOP = 2;
- // Used to determine reset of mSetOrientationRequestCounter if next app requested
- // orientation is after timeout value
- @VisibleForTesting
- static final int SET_ORIENTATION_REQUEST_COUNTER_TIMEOUT_MS = 1000;
-
private final Point mTmpPoint = new Point();
private final LetterboxConfiguration mLetterboxConfiguration;
@@ -159,43 +106,9 @@
// TODO(b/265576778): Cache other overrides as well.
- // Corresponds to OVERRIDE_ANY_ORIENTATION
- private final boolean mIsOverrideAnyOrientationEnabled;
- // Corresponds to OVERRIDE_ANY_ORIENTATION_TO_USER
- private final boolean mIsSystemOverrideToFullscreenEnabled;
- // Corresponds to OVERRIDE_UNDEFINED_ORIENTATION_TO_PORTRAIT
- private final boolean mIsOverrideToPortraitOrientationEnabled;
- // Corresponds to OVERRIDE_UNDEFINED_ORIENTATION_TO_NOSENSOR
- private final boolean mIsOverrideToNosensorOrientationEnabled;
- // Corresponds to OVERRIDE_LANDSCAPE_ORIENTATION_TO_REVERSE_LANDSCAPE
- private final boolean mIsOverrideToReverseLandscapeOrientationEnabled;
- // Corresponds to OVERRIDE_ORIENTATION_ONLY_FOR_CAMERA
- private final boolean mIsOverrideOrientationOnlyForCameraEnabled;
- // Corresponds to OVERRIDE_RESPECT_REQUESTED_ORIENTATION
- private final boolean mIsOverrideRespectRequestedOrientationEnabled;
-
- @NonNull
- private final OptProp mAllowOrientationOverrideOptProp;
- @NonNull
- private final OptProp mAllowDisplayOrientationOverrideOptProp;
- @NonNull
- private final OptProp mAllowMinAspectRatioOverrideOptProp;
- @NonNull
- private final OptProp mAllowForceResizeOverrideOptProp;
-
- @NonNull
- private final OptProp mAllowUserAspectRatioOverrideOptProp;
- @NonNull
- private final OptProp mAllowUserAspectRatioFullscreenOverrideOptProp;
private boolean mShowWallpaperForLetterboxBackground;
- // Updated when ActivityRecord#setRequestedOrientation is called
- private long mTimeMsLastSetOrientationRequest = 0;
-
- // Counter for ActivityRecord#setRequestedOrientation
- private int mSetOrientationRequestCounter = 0;
-
// TODO(b/315140179): Make mUserAspectRatio final
// The min aspect ratio override set by user
@PackageManager.UserMinAspectRatio
@@ -204,31 +117,11 @@
@Nullable
private Letterbox mLetterbox;
- @NonNull
- private final OptProp mCameraCompatAllowForceRotationOptProp;
-
- @NonNull
- private final OptProp mCameraCompatAllowRefreshOptProp;
-
- @NonNull
- private final OptProp mCameraCompatEnableRefreshViaPauseOptProp;
-
// Whether activity "refresh" was requested but not finished in
// ActivityRecord#activityResumedLocked following the camera compat force rotation in
// DisplayRotationCompatPolicy.
private boolean mIsRefreshRequested;
- @NonNull
- private final OptProp mIgnoreRequestedOrientationOptProp;
-
- @NonNull
- private final OptProp mAllowIgnoringOrientationRequestWhenLoopDetectedOptProp;
-
- @NonNull
- private final OptProp mFakeFocusOptProp;
-
- private boolean mIsRelaunchingAfterRequestedOrientationChanged;
-
private boolean mLastShouldShowLetterboxUi;
private boolean mDoubleTapEvent;
@@ -242,76 +135,6 @@
// is created in its constructor. It shouldn't be used in this constructor but it's safe
// to use it after since controller is only used in ActivityRecord.
mActivityRecord = activityRecord;
-
- PackageManager packageManager = wmService.mContext.getPackageManager();
-
- final OptPropFactory optPropBuilder = new OptPropFactory(packageManager,
- activityRecord.packageName);
-
- final BooleanSupplier isPolicyForIgnoringRequestedOrientationEnabled = asLazy(
- mLetterboxConfiguration::isPolicyForIgnoringRequestedOrientationEnabled);
- mIgnoreRequestedOrientationOptProp = optPropBuilder.create(
- PROPERTY_COMPAT_IGNORE_REQUESTED_ORIENTATION,
- isPolicyForIgnoringRequestedOrientationEnabled);
- mAllowIgnoringOrientationRequestWhenLoopDetectedOptProp = optPropBuilder.create(
- PROPERTY_COMPAT_ALLOW_IGNORING_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED,
- isPolicyForIgnoringRequestedOrientationEnabled);
-
- mFakeFocusOptProp = optPropBuilder.create(PROPERTY_COMPAT_ENABLE_FAKE_FOCUS,
- mLetterboxConfiguration::isCompatFakeFocusEnabled);
-
- final BooleanSupplier isCameraCompatTreatmentEnabled = asLazy(
- mLetterboxConfiguration::isCameraCompatTreatmentEnabled);
- mCameraCompatAllowForceRotationOptProp = optPropBuilder.create(
- PROPERTY_CAMERA_COMPAT_ALLOW_FORCE_ROTATION,
- isCameraCompatTreatmentEnabled);
- mCameraCompatAllowRefreshOptProp = optPropBuilder.create(
- PROPERTY_CAMERA_COMPAT_ALLOW_REFRESH,
- isCameraCompatTreatmentEnabled);
- mCameraCompatEnableRefreshViaPauseOptProp = optPropBuilder.create(
- PROPERTY_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE,
- isCameraCompatTreatmentEnabled);
-
- mAllowOrientationOverrideOptProp = optPropBuilder.create(
- PROPERTY_COMPAT_ALLOW_ORIENTATION_OVERRIDE);
-
- mAllowDisplayOrientationOverrideOptProp = optPropBuilder.create(
- PROPERTY_COMPAT_ALLOW_DISPLAY_ORIENTATION_OVERRIDE,
- () -> mActivityRecord.mDisplayContent != null
- && mActivityRecord.getTask() != null
- && mActivityRecord.mDisplayContent.getIgnoreOrientationRequest()
- && !mActivityRecord.getTask().inMultiWindowMode()
- && mActivityRecord.mDisplayContent.getNaturalOrientation()
- == ORIENTATION_LANDSCAPE
- );
-
- mAllowMinAspectRatioOverrideOptProp = optPropBuilder.create(
- PROPERTY_COMPAT_ALLOW_MIN_ASPECT_RATIO_OVERRIDE);
-
- mAllowForceResizeOverrideOptProp = optPropBuilder.create(
- PROPERTY_COMPAT_ALLOW_RESIZEABLE_ACTIVITY_OVERRIDES);
-
- mAllowUserAspectRatioOverrideOptProp = optPropBuilder.create(
- PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_OVERRIDE,
- mLetterboxConfiguration::isUserAppAspectRatioSettingsEnabled);
-
- mAllowUserAspectRatioFullscreenOverrideOptProp = optPropBuilder.create(
- PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_FULLSCREEN_OVERRIDE,
- mLetterboxConfiguration::isUserAppAspectRatioFullscreenEnabled);
-
- mIsOverrideAnyOrientationEnabled = isCompatChangeEnabled(OVERRIDE_ANY_ORIENTATION);
- mIsSystemOverrideToFullscreenEnabled =
- isCompatChangeEnabled(OVERRIDE_ANY_ORIENTATION_TO_USER);
- mIsOverrideToPortraitOrientationEnabled =
- isCompatChangeEnabled(OVERRIDE_UNDEFINED_ORIENTATION_TO_PORTRAIT);
- mIsOverrideToReverseLandscapeOrientationEnabled =
- isCompatChangeEnabled(OVERRIDE_LANDSCAPE_ORIENTATION_TO_REVERSE_LANDSCAPE);
- mIsOverrideToNosensorOrientationEnabled =
- isCompatChangeEnabled(OVERRIDE_UNDEFINED_ORIENTATION_TO_NOSENSOR);
- mIsOverrideOrientationOnlyForCameraEnabled =
- isCompatChangeEnabled(OVERRIDE_ORIENTATION_ONLY_FOR_CAMERA);
- mIsOverrideRespectRequestedOrientationEnabled =
- isCompatChangeEnabled(OVERRIDE_RESPECT_REQUESTED_ORIENTATION);
}
/** Cleans up {@link Letterbox} if it exists.*/
@@ -320,7 +143,6 @@
mLetterbox.destroy();
mLetterbox = null;
}
- mActivityRecord.mTransparentPolicy.stop();
}
void onMovedToDisplay(int displayId) {
@@ -330,60 +152,6 @@
}
/**
- * Whether should ignore app requested orientation in response to an app
- * calling {@link android.app.Activity#setRequestedOrientation}.
- *
- * <p>This is needed to avoid getting into {@link android.app.Activity#setRequestedOrientation}
- * loop when {@link DisplayContent#getIgnoreOrientationRequest} is enabled or device has
- * landscape natural orientation which app developers don't expect. For example, the loop can
- * look like this:
- * <ol>
- * <li>App sets default orientation to "unspecified" at runtime
- * <li>App requests to "portrait" after checking some condition (e.g. display rotation).
- * <li>(2) leads to fullscreen -> letterboxed bounds change and activity relaunch because
- * app can't handle the corresponding config changes.
- * <li>Loop goes back to (1)
- * </ol>
- *
- * <p>This treatment is enabled when the following conditions are met:
- * <ul>
- * <li>Flag gating the treatment is enabled
- * <li>Opt-out component property isn't enabled
- * <li>Opt-in component property or per-app override are enabled
- * <li>Activity is relaunched after {@link android.app.Activity#setRequestedOrientation}
- * call from an app or camera compat force rotation treatment is active for the activity.
- * <li>Orientation request loop detected and is not letterboxed for fixed orientation
- * </ul>
- */
- boolean shouldIgnoreRequestedOrientation(@ScreenOrientation int requestedOrientation) {
- if (mIgnoreRequestedOrientationOptProp.shouldEnableWithOverrideAndProperty(
- isCompatChangeEnabled(OVERRIDE_ENABLE_COMPAT_IGNORE_REQUESTED_ORIENTATION))) {
- if (mIsRelaunchingAfterRequestedOrientationChanged) {
- Slog.w(TAG, "Ignoring orientation update to "
- + screenOrientationToString(requestedOrientation)
- + " due to relaunching after setRequestedOrientation for "
- + mActivityRecord);
- return true;
- }
- if (isCameraCompatTreatmentActive()) {
- Slog.w(TAG, "Ignoring orientation update to "
- + screenOrientationToString(requestedOrientation)
- + " due to camera compat treatment for " + mActivityRecord);
- return true;
- }
- }
-
- if (shouldIgnoreOrientationRequestLoop()) {
- Slog.w(TAG, "Ignoring orientation update to "
- + screenOrientationToString(requestedOrientation)
- + " as orientation request loop was detected for "
- + mActivityRecord);
- return true;
- }
- return false;
- }
-
- /**
* Whether an app is calling {@link android.app.Activity#setRequestedOrientation}
* in a loop and orientation request should be ignored.
*
@@ -401,31 +169,14 @@
* </ul>
*/
boolean shouldIgnoreOrientationRequestLoop() {
- final boolean loopDetectionEnabled = isCompatChangeEnabled(
- OVERRIDE_ENABLE_COMPAT_IGNORE_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED);
- if (!mAllowIgnoringOrientationRequestWhenLoopDetectedOptProp
- .shouldEnableWithOptInOverrideAndOptOutProperty(loopDetectionEnabled)) {
- return false;
- }
-
- final long currTimeMs = System.currentTimeMillis();
- if (currTimeMs - mTimeMsLastSetOrientationRequest
- < SET_ORIENTATION_REQUEST_COUNTER_TIMEOUT_MS) {
- mSetOrientationRequestCounter += 1;
- } else {
- // Resets app setOrientationRequest counter if timed out
- mSetOrientationRequestCounter = 0;
- }
- // Update time last called
- mTimeMsLastSetOrientationRequest = currTimeMs;
-
- return mSetOrientationRequestCounter >= MIN_COUNT_TO_IGNORE_REQUEST_IN_LOOP
- && !mActivityRecord.isLetterboxedForFixedOrientationAndAspectRatio();
+ return getAppCompatCapability().getAppCompatOrientationCapability()
+ .shouldIgnoreOrientationRequestLoop();
}
@VisibleForTesting
int getSetOrientationRequestCounter() {
- return mSetOrientationRequestCounter;
+ return getAppCompatCapability().getAppCompatOrientationCapability()
+ .getSetOrientationRequestCounter();
}
/**
@@ -441,8 +192,7 @@
* </ul>
*/
boolean shouldSendFakeFocus() {
- return mFakeFocusOptProp.shouldEnableWithOverrideAndProperty(
- isCompatChangeEnabled(OVERRIDE_ENABLE_COMPAT_FAKE_FOCUS));
+ return getAppCompatCapability().shouldSendFakeFocus();
}
/**
@@ -458,8 +208,7 @@
* </ul>
*/
boolean shouldOverrideMinAspectRatio() {
- return mAllowMinAspectRatioOverrideOptProp.shouldEnableWithOptInOverrideAndOptOutProperty(
- isCompatChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO));
+ return getAppCompatCapability().shouldOverrideMinAspectRatio();
}
/**
@@ -476,10 +225,7 @@
* </ul>
*/
boolean shouldOverrideMinAspectRatioForCamera() {
- return mActivityRecord.isCameraActive()
- && mAllowMinAspectRatioOverrideOptProp
- .shouldEnableWithOptInOverrideAndOptOutProperty(
- isCompatChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO_ONLY_FOR_CAMERA));
+ return getAppCompatCapability().shouldOverrideMinAspectRatioForCamera();
}
/**
@@ -495,8 +241,7 @@
* </ul>
*/
boolean shouldOverrideForceResizeApp() {
- return mAllowForceResizeOverrideOptProp.shouldEnableWithOptInOverrideAndOptOutProperty(
- isCompatChangeEnabled(FORCE_RESIZE_APP));
+ return getAppCompatCapability().shouldOverrideForceResizeApp();
}
/**
@@ -510,8 +255,7 @@
* </ul>
*/
boolean shouldOverrideForceNonResizeApp() {
- return mAllowForceResizeOverrideOptProp.shouldEnableWithOptInOverrideAndOptOutProperty(
- isCompatChangeEnabled(FORCE_NON_RESIZE_APP));
+ return getAppCompatCapability().shouldOverrideForceNonResizeApp();
}
/**
@@ -519,7 +263,8 @@
* android.app.Activity#setRequestedOrientation}.
*/
void setRelaunchingAfterRequestedOrientationChanged(boolean isRelaunching) {
- mIsRelaunchingAfterRequestedOrientationChanged = isRelaunching;
+ getAppCompatCapability().getAppCompatOrientationCapability()
+ .setRelaunchingAfterRequestedOrientationChanged(isRelaunching);
}
/**
@@ -534,7 +279,7 @@
}
boolean isOverrideRespectRequestedOrientationEnabled() {
- return mIsOverrideRespectRequestedOrientationEnabled;
+ return getAppCompatCapability().isOverrideRespectRequestedOrientationEnabled();
}
/**
@@ -551,101 +296,17 @@
* </ul>
*/
boolean shouldUseDisplayLandscapeNaturalOrientation() {
- return mAllowDisplayOrientationOverrideOptProp
- .shouldEnableWithOptInOverrideAndOptOutProperty(
- isCompatChangeEnabled(OVERRIDE_USE_DISPLAY_LANDSCAPE_NATURAL_ORIENTATION));
+ return getAppCompatCapability().shouldUseDisplayLandscapeNaturalOrientation();
}
@ScreenOrientation
int overrideOrientationIfNeeded(@ScreenOrientation int candidate) {
- final DisplayContent displayContent = mActivityRecord.mDisplayContent;
- final boolean isIgnoreOrientationRequestEnabled = displayContent != null
- && displayContent.getIgnoreOrientationRequest();
- if (shouldApplyUserFullscreenOverride() && isIgnoreOrientationRequestEnabled
- // Do not override orientation to fullscreen for camera activities.
- // Fixed-orientation activities are rarely tested in other orientations, and it
- // often results in sideways or stretched previews. As the camera compat treatment
- // targets fixed-orientation activities, overriding the orientation disables the
- // treatment.
- && !mActivityRecord.isCameraActive()) {
- Slog.v(TAG, "Requested orientation " + screenOrientationToString(candidate) + " for "
- + mActivityRecord + " is overridden to "
- + screenOrientationToString(SCREEN_ORIENTATION_USER)
- + " by user aspect ratio settings.");
- return SCREEN_ORIENTATION_USER;
- }
-
- // In some cases (e.g. Kids app) we need to map the candidate orientation to some other
- // orientation.
- candidate = mActivityRecord.mWmService.mapOrientationRequest(candidate);
-
- if (shouldApplyUserMinAspectRatioOverride() && (!isFixedOrientation(candidate)
- || candidate == SCREEN_ORIENTATION_LOCKED)) {
- Slog.v(TAG, "Requested orientation " + screenOrientationToString(candidate) + " for "
- + mActivityRecord + " is overridden to "
- + screenOrientationToString(SCREEN_ORIENTATION_PORTRAIT)
- + " by user aspect ratio settings.");
- return SCREEN_ORIENTATION_PORTRAIT;
- }
-
- if (mAllowOrientationOverrideOptProp.isFalse()) {
- return candidate;
- }
-
- if (mIsOverrideOrientationOnlyForCameraEnabled && displayContent != null
- && (displayContent.mDisplayRotationCompatPolicy == null
- || !displayContent.mDisplayRotationCompatPolicy
- .isActivityEligibleForOrientationOverride(mActivityRecord))) {
- return candidate;
- }
-
- // mUserAspectRatio is always initialized first in shouldApplyUserFullscreenOverride(),
- // which will always come first before this check as user override > device
- // manufacturer override.
- if (isSystemOverrideToFullscreenEnabled() && isIgnoreOrientationRequestEnabled
- // Do not override orientation to fullscreen for camera activities.
- // Fixed-orientation activities are rarely tested in other orientations, and it
- // often results in sideways or stretched previews. As the camera compat treatment
- // targets fixed-orientation activities, overriding the orientation disables the
- // treatment.
- && !mActivityRecord.isCameraActive()) {
- Slog.v(TAG, "Requested orientation " + screenOrientationToString(candidate) + " for "
- + mActivityRecord + " is overridden to "
- + screenOrientationToString(SCREEN_ORIENTATION_USER));
- return SCREEN_ORIENTATION_USER;
- }
-
- if (mIsOverrideToReverseLandscapeOrientationEnabled
- && (isFixedOrientationLandscape(candidate) || mIsOverrideAnyOrientationEnabled)) {
- Slog.w(TAG, "Requested orientation " + screenOrientationToString(candidate) + " for "
- + mActivityRecord + " is overridden to "
- + screenOrientationToString(SCREEN_ORIENTATION_REVERSE_LANDSCAPE));
- return SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
- }
-
- if (!mIsOverrideAnyOrientationEnabled && isFixedOrientation(candidate)) {
- return candidate;
- }
-
- if (mIsOverrideToPortraitOrientationEnabled) {
- Slog.w(TAG, "Requested orientation " + screenOrientationToString(candidate) + " for "
- + mActivityRecord + " is overridden to "
- + screenOrientationToString(SCREEN_ORIENTATION_PORTRAIT));
- return SCREEN_ORIENTATION_PORTRAIT;
- }
-
- if (mIsOverrideToNosensorOrientationEnabled) {
- Slog.w(TAG, "Requested orientation " + screenOrientationToString(candidate) + " for "
- + mActivityRecord + " is overridden to "
- + screenOrientationToString(SCREEN_ORIENTATION_NOSENSOR));
- return SCREEN_ORIENTATION_NOSENSOR;
- }
-
- return candidate;
+ return mActivityRecord.mAppCompatController.getOrientationPolicy()
+ .overrideOrientationIfNeeded(candidate);
}
boolean isOverrideOrientationOnlyForCameraEnabled() {
- return mIsOverrideOrientationOnlyForCameraEnabled;
+ return getAppCompatCapability().isOverrideOrientationOnlyForCameraEnabled();
}
/**
@@ -660,8 +321,7 @@
* </ul>
*/
boolean shouldRefreshActivityForCameraCompat() {
- return mCameraCompatAllowRefreshOptProp.shouldEnableWithOptOutOverrideAndProperty(
- isCompatChangeEnabled(OVERRIDE_CAMERA_COMPAT_DISABLE_REFRESH));
+ return getAppCompatCapability().shouldRefreshActivityForCameraCompat();
}
/**
@@ -679,8 +339,7 @@
* </ul>
*/
boolean shouldRefreshActivityViaPauseForCameraCompat() {
- return mCameraCompatEnableRefreshViaPauseOptProp.shouldEnableWithOverrideAndProperty(
- isCompatChangeEnabled(OVERRIDE_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE));
+ return getAppCompatCapability().shouldRefreshActivityViaPauseForCameraCompat();
}
/**
@@ -695,8 +354,7 @@
* </ul>
*/
boolean shouldForceRotateForCameraCompat() {
- return mCameraCompatAllowForceRotationOptProp.shouldEnableWithOptOutOverrideAndProperty(
- isCompatChangeEnabled(OVERRIDE_CAMERA_COMPAT_DISABLE_FORCE_ROTATION));
+ return getAppCompatCapability().shouldForceRotateForCameraCompat();
}
/**
@@ -714,18 +372,7 @@
* </ul>
*/
boolean shouldApplyFreeformTreatmentForCameraCompat() {
- return Flags.cameraCompatForFreeform() && !isCompatChangeEnabled(
- OVERRIDE_CAMERA_COMPAT_DISABLE_FREEFORM_WINDOWING_TREATMENT);
- }
-
- private boolean isCameraCompatTreatmentActive() {
- DisplayContent displayContent = mActivityRecord.mDisplayContent;
- if (displayContent == null) {
- return false;
- }
- return displayContent.mDisplayRotationCompatPolicy != null
- && displayContent.mDisplayRotationCompatPolicy
- .isTreatmentEnabledForActivity(mActivityRecord);
+ return getAppCompatCapability().shouldApplyFreeformTreatmentForCameraCompat();
}
@FreeformCameraCompatMode
@@ -785,16 +432,18 @@
}
void updateLetterboxSurfaceIfNeeded(WindowState winHint) {
- updateLetterboxSurfaceIfNeeded(winHint, mActivityRecord.getSyncTransaction());
+ updateLetterboxSurfaceIfNeeded(winHint, mActivityRecord.getSyncTransaction(),
+ mActivityRecord.getPendingTransaction());
}
- void updateLetterboxSurfaceIfNeeded(WindowState winHint, Transaction t) {
+ void updateLetterboxSurfaceIfNeeded(WindowState winHint, @NonNull Transaction t,
+ @NonNull Transaction inputT) {
if (shouldNotLayoutLetterbox(winHint)) {
return;
}
layoutLetterboxIfNeeded(winHint);
if (mLetterbox != null && mLetterbox.needsApplySurfaceChanges()) {
- mLetterbox.applySurfaceChanges(t);
+ mLetterbox.applySurfaceChanges(t, inputT);
}
}
@@ -850,7 +499,8 @@
// For this reason we use ActivityRecord#getBounds() that the translucent activity
// inherits from the first opaque activity beneath and also takes care of the scaling
// in case of activities in size compat mode.
- final Rect innerFrame = mActivityRecord.mTransparentPolicy.isRunning()
+ final Rect innerFrame = mActivityRecord.mAppCompatController
+ .getTransparentPolicy().isRunning()
? mActivityRecord.getBounds() : w.getFrame();
mLetterbox.layout(spaceToFill, innerFrame, mTmpPoint);
if (mDoubleTapEvent) {
@@ -987,7 +637,7 @@
// Don't resize to split screen size when in book mode if letterbox position is centered
return (isBookMode && isNotCenteredHorizontally || isTabletopMode && isLandscape)
|| isCameraCompatSplitScreenAspectRatioAllowed()
- && isCameraCompatTreatmentActive();
+ && getAppCompatCapability().isCameraCompatTreatmentActive();
}
private float getDefaultMinAspectRatioForUnresizableApps() {
@@ -1089,13 +739,7 @@
* Whether we should enable users to resize the current app.
*/
boolean shouldEnableUserAspectRatioSettings() {
- // We use mBooleanPropertyAllowUserAspectRatioOverride to allow apps to opt-out which has
- // effect only if explicitly false. If mBooleanPropertyAllowUserAspectRatioOverride is null,
- // the current app doesn't opt-out so the first part of the predicate is true.
- return !mAllowUserAspectRatioOverrideOptProp.isFalse()
- && mLetterboxConfiguration.isUserAppAspectRatioSettingsEnabled()
- && mActivityRecord.mDisplayContent != null
- && mActivityRecord.mDisplayContent.getIgnoreOrientationRequest();
+ return getAppCompatCapability().shouldEnableUserAspectRatioSettings();
}
/**
@@ -1114,15 +758,6 @@
&& mUserAspectRatio != USER_MIN_ASPECT_RATIO_FULLSCREEN;
}
- boolean isUserFullscreenOverrideEnabled() {
- if (mAllowUserAspectRatioOverrideOptProp.isFalse()
- || mAllowUserAspectRatioFullscreenOverrideOptProp.isFalse()
- || !mLetterboxConfiguration.isUserAppAspectRatioFullscreenEnabled()) {
- return false;
- }
- return true;
- }
-
boolean shouldApplyUserFullscreenOverride() {
if (isUserFullscreenOverrideEnabled()) {
mUserAspectRatio = getUserMinAspectRatioOverrideCode();
@@ -1133,11 +768,12 @@
return false;
}
+ boolean isUserFullscreenOverrideEnabled() {
+ return getAppCompatCapability().isUserFullscreenOverrideEnabled();
+ }
+
boolean isSystemOverrideToFullscreenEnabled() {
- return mIsSystemOverrideToFullscreenEnabled
- && !mAllowOrientationOverrideOptProp.isFalse()
- && (mUserAspectRatio == USER_MIN_ASPECT_RATIO_UNSET
- || mUserAspectRatio == USER_MIN_ASPECT_RATIO_FULLSCREEN);
+ return getAppCompatCapability().isSystemOverrideToFullscreenEnabled(mUserAspectRatio);
}
boolean hasFullscreenOverride() {
@@ -1311,8 +947,9 @@
? parentAppBoundsOverride : parentConfiguration.windowConfiguration.getAppBounds();
// Use screen resolved bounds which uses resolved bounds or size compat bounds
// as activity bounds can sometimes be empty
- final Rect opaqueActivityBounds = mActivityRecord.mTransparentPolicy
- .getFirstOpaqueActivity().map(ActivityRecord::getScreenResolvedBounds)
+ final Rect opaqueActivityBounds = mActivityRecord.mAppCompatController
+ .getTransparentPolicy().getFirstOpaqueActivity()
+ .map(ActivityRecord::getScreenResolvedBounds)
.orElse(mActivityRecord.getScreenResolvedBounds());
return mLetterboxConfiguration.getIsHorizontalReachabilityEnabled()
&& parentConfiguration.windowConfiguration.getWindowingMode()
@@ -1331,6 +968,11 @@
return isHorizontalReachabilityEnabled() || isVerticalReachabilityEnabled();
}
+ // TODO(b/346264992): Remove after AppCompatController refactoring
+ private AppCompatCapability getAppCompatCapability() {
+ return mActivityRecord.mAppCompatController.getAppCompatCapability();
+ }
+
/**
* Whether vertical reachability is enabled for an activity in the current configuration.
*
@@ -1350,8 +992,9 @@
? parentAppBoundsOverride : parentConfiguration.windowConfiguration.getAppBounds();
// Use screen resolved bounds which uses resolved bounds or size compat bounds
// as activity bounds can sometimes be empty.
- final Rect opaqueActivityBounds = mActivityRecord.mTransparentPolicy
- .getFirstOpaqueActivity().map(ActivityRecord::getScreenResolvedBounds)
+ final Rect opaqueActivityBounds = mActivityRecord.mAppCompatController
+ .getTransparentPolicy().getFirstOpaqueActivity()
+ .map(ActivityRecord::getScreenResolvedBounds)
.orElse(mActivityRecord.getScreenResolvedBounds());
return mLetterboxConfiguration.getIsVerticalReachabilityEnabled()
&& parentConfiguration.windowConfiguration.getWindowingMode()
@@ -1368,7 +1011,8 @@
@VisibleForTesting
boolean shouldShowLetterboxUi(WindowState mainWindow) {
- if (mIsRelaunchingAfterRequestedOrientationChanged) {
+ if (getAppCompatCapability().getAppCompatOrientationCapability()
+ .getIsRelaunchingAfterRequestedOrientationChanged()) {
return mLastShouldShowLetterboxUi;
}
@@ -1457,7 +1101,7 @@
// corners because we assume the specific layout would. This is the case when the layout
// of the translucent activity uses only a part of all the bounds because of the use of
// LayoutParams.WRAP_CONTENT.
- if (mActivityRecord.mTransparentPolicy.isRunning()
+ if (mActivityRecord.mAppCompatController.getTransparentPolicy().isRunning()
&& (cropBounds.width() != mainWindow.mRequestedWidth
|| cropBounds.height() != mainWindow.mRequestedHeight)) {
return null;
@@ -1528,7 +1172,8 @@
}
boolean getIsRelaunchingAfterRequestedOrientationChanged() {
- return mIsRelaunchingAfterRequestedOrientationChanged;
+ return getAppCompatCapability().getAppCompatOrientationCapability()
+ .getIsRelaunchingAfterRequestedOrientationChanged();
}
private void adjustBoundsForTaskbar(final WindowState mainWindow, final Rect bounds) {
@@ -1713,13 +1358,13 @@
int getLetterboxPositionForLogging() {
int positionToLog = APP_COMPAT_STATE_CHANGED__LETTERBOX_POSITION__UNKNOWN_POSITION;
if (isHorizontalReachabilityEnabled()) {
- int letterboxPositionForHorizontalReachability = getLetterboxConfiguration()
+ int letterboxPositionForHorizontalReachability = mLetterboxConfiguration
.getLetterboxPositionForHorizontalReachability(
isDisplayFullScreenAndInPosture(/* isTabletop */ false));
positionToLog = letterboxHorizontalReachabilityPositionToLetterboxPosition(
letterboxPositionForHorizontalReachability);
} else if (isVerticalReachabilityEnabled()) {
- int letterboxPositionForVerticalReachability = getLetterboxConfiguration()
+ int letterboxPositionForVerticalReachability = mLetterboxConfiguration
.getLetterboxPositionForVerticalReachability(
isDisplayFullScreenAndInPosture(/* isTabletop */ true));
positionToLog = letterboxVerticalReachabilityPositionToLetterboxPosition(
@@ -1728,10 +1373,6 @@
return positionToLog;
}
- private LetterboxConfiguration getLetterboxConfiguration() {
- return mLetterboxConfiguration;
- }
-
/**
* Logs letterbox position changes via {@link ActivityMetricsLogger#logLetterboxPositionChange}.
*/
@@ -1761,21 +1402,4 @@
w.mAttrs.insetsFlags.appearance
);
}
-
- @NonNull
- private static BooleanSupplier asLazy(@NonNull BooleanSupplier supplier) {
- return new BooleanSupplier() {
- private boolean mRead;
- private boolean mValue;
-
- @Override
- public boolean getAsBoolean() {
- if (!mRead) {
- mRead = true;
- mValue = supplier.getAsBoolean();
- }
- return mValue;
- }
- };
- }
}
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 3b3eeb4..4a0239b 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -41,7 +41,6 @@
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_POSITIONING;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
-import static com.android.window.flags.Flags.windowSessionRelayoutInfo;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -64,7 +63,6 @@
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.ArraySet;
-import android.util.MergedConfiguration;
import android.util.Slog;
import android.view.IWindow;
import android.view.IWindowId;
@@ -81,7 +79,6 @@
import android.view.WindowInsets.Type.InsetsType;
import android.view.WindowManager;
import android.view.WindowRelayoutResult;
-import android.window.ClientWindowFrames;
import android.window.InputTransferToken;
import android.window.OnBackInvokedCallbackInfo;
@@ -290,37 +287,12 @@
return res;
}
- /** @deprecated */
- @Deprecated
- @Override
- public int relayoutLegacy(IWindow window, WindowManager.LayoutParams attrs,
- int requestedWidth, int requestedHeight, int viewFlags, int flags, int seq,
- int lastSyncSeqId, ClientWindowFrames outFrames,
- MergedConfiguration mergedConfiguration, SurfaceControl outSurfaceControl,
- InsetsState outInsetsState, InsetsSourceControl.Array outActiveControls,
- Bundle outBundle) {
- Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, mRelayoutTag);
- int res = mService.relayoutWindow(this, window, attrs,
- requestedWidth, requestedHeight, viewFlags, flags, seq,
- lastSyncSeqId, outFrames, mergedConfiguration, outSurfaceControl, outInsetsState,
- outActiveControls, outBundle);
- Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
- return res;
- }
-
@Override
public void relayoutAsync(IWindow window, WindowManager.LayoutParams attrs,
int requestedWidth, int requestedHeight, int viewFlags, int flags, int seq,
int lastSyncSeqId) {
- if (windowSessionRelayoutInfo()) {
- relayout(window, attrs, requestedWidth, requestedHeight, viewFlags, flags, seq,
- lastSyncSeqId, null /* outRelayoutResult */);
- } else {
- relayoutLegacy(window, attrs, requestedWidth, requestedHeight, viewFlags, flags, seq,
- lastSyncSeqId, null /* outFrames */, null /* mergedConfiguration */,
- null /* outSurfaceControl */, null /* outInsetsState */,
- null /* outActiveControls */, null /* outSyncIdBundle */);
- }
+ relayout(window, attrs, requestedWidth, requestedHeight, viewFlags, flags, seq,
+ lastSyncSeqId, null /* outRelayoutResult */);
}
@Override
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index ab72e3c..acdb66a 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -29,6 +29,7 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.app.WindowConfiguration.isFloating;
import static android.content.pm.ActivityInfo.FLAG_ALLOW_UNTRUSTED_ACTIVITY_EMBEDDING;
import static android.content.pm.ActivityInfo.FLAG_RESUME_WHILE_PAUSING;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
@@ -2241,15 +2242,17 @@
static class ConfigOverrideHint {
@Nullable DisplayInfo mTmpOverrideDisplayInfo;
@Nullable ActivityRecord.CompatDisplayInsets mTmpCompatInsets;
- @Nullable Rect mTmpParentAppBoundsOverride;
+ @Nullable Rect mParentAppBoundsOverride;
int mTmpOverrideConfigOrientation;
boolean mUseOverrideInsetsForConfig;
void resolveTmpOverrides(DisplayContent dc, Configuration parentConfig,
boolean isFixedRotationTransforming) {
- mTmpParentAppBoundsOverride = new Rect(parentConfig.windowConfiguration.getAppBounds());
+ mParentAppBoundsOverride = new Rect(parentConfig.windowConfiguration.getAppBounds());
+ mTmpOverrideConfigOrientation = parentConfig.orientation;
final Insets insets;
- if (mUseOverrideInsetsForConfig && dc != null) {
+ if (mUseOverrideInsetsForConfig && dc != null
+ && !isFloating(parentConfig.windowConfiguration.getWindowingMode())) {
// Insets are decoupled from configuration by default from V+, use legacy
// compatibility behaviour for apps targeting SDK earlier than 35
// (see applySizeOverrideIfNeeded).
@@ -2269,13 +2272,12 @@
} else {
insets = Insets.NONE;
}
- mTmpParentAppBoundsOverride.inset(insets);
+ mParentAppBoundsOverride.inset(insets);
}
void resetTmpOverrides() {
mTmpOverrideDisplayInfo = null;
mTmpCompatInsets = null;
- mTmpParentAppBoundsOverride = null;
mTmpOverrideConfigOrientation = ORIENTATION_UNDEFINED;
}
}
@@ -2364,7 +2366,7 @@
final Rect containingAppBounds;
if (insideParentBounds) {
containingAppBounds = useOverrideInsetsForConfig
- ? overrideHint.mTmpParentAppBoundsOverride
+ ? overrideHint.mParentAppBoundsOverride
: parentConfig.windowConfiguration.getAppBounds();
} else {
// Restrict appBounds to display non-decor rather than parent because the
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index 65239ef..a029f38 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -1903,7 +1903,10 @@
} else {
final List<TransitionInfo.Change> changes = info.getChanges();
for (int i = changes.size() - 1; i >= 0; --i) {
- if (mTargets.get(i).mContainer.asActivityRecord() != null) {
+ final WindowContainer<?> container = mTargets.get(i).mContainer;
+ if (container.asActivityRecord() != null
+ || (container.asTask() != null
+ && mOverrideOptions.getOverrideTaskTransition())) {
changes.get(i).setAnimationOptions(mOverrideOptions);
// TODO(b/295805497): Extract mBackgroundColor from AnimationOptions.
changes.get(i).setBackgroundColor(mOverrideOptions.getBackgroundColor());
diff --git a/services/core/java/com/android/server/wm/TransparentPolicy.java b/services/core/java/com/android/server/wm/TransparentPolicy.java
index b408397..3044abd 100644
--- a/services/core/java/com/android/server/wm/TransparentPolicy.java
+++ b/services/core/java/com/android/server/wm/TransparentPolicy.java
@@ -260,8 +260,9 @@
private void start(@NonNull ActivityRecord firstOpaqueActivity) {
mFirstOpaqueActivity = firstOpaqueActivity;
- mFirstOpaqueActivity.mTransparentPolicy
- .mDestroyListeners.add(mActivityRecord.mTransparentPolicy);
+ mFirstOpaqueActivity.mAppCompatController.getTransparentPolicy()
+ .mDestroyListeners.add(mActivityRecord.mAppCompatController
+ .getTransparentPolicy());
inheritFromOpaque(firstOpaqueActivity);
final WindowContainer<?> parent = mActivityRecord.getParent();
mLetterboxConfigListener = WindowContainer.overrideConfigurationPropagation(
@@ -312,8 +313,9 @@
mInheritedAppCompatState = APP_COMPAT_STATE_CHANGED__STATE__UNKNOWN;
mInheritedCompatDisplayInsets = null;
if (mFirstOpaqueActivity != null) {
- mFirstOpaqueActivity.mTransparentPolicy
- .mDestroyListeners.remove(mActivityRecord.mTransparentPolicy);
+ mFirstOpaqueActivity.mAppCompatController.getTransparentPolicy()
+ .mDestroyListeners.remove(mActivityRecord.mAppCompatController
+ .getTransparentPolicy());
}
mFirstOpaqueActivity = null;
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 2b375e1..72ec058 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2292,32 +2292,7 @@
outInsetsState = null;
outActiveControls = null;
}
- return relayoutWindowInner(session, client, attrs, requestedWidth, requestedHeight,
- viewVisibility, flags, seq, lastSyncSeqId, outFrames, outMergedConfiguration,
- outSurfaceControl, outInsetsState, outActiveControls, null /* outBundle */,
- outRelayoutResult);
- }
- /** @deprecated */
- @Deprecated
- public int relayoutWindow(Session session, IWindow client, LayoutParams attrs,
- int requestedWidth, int requestedHeight, int viewVisibility, int flags, int seq,
- int lastSyncSeqId, ClientWindowFrames outFrames,
- MergedConfiguration outMergedConfiguration, SurfaceControl outSurfaceControl,
- InsetsState outInsetsState, InsetsSourceControl.Array outActiveControls,
- Bundle outBundle) {
- return relayoutWindowInner(session, client, attrs, requestedWidth, requestedHeight,
- viewVisibility, flags, seq, lastSyncSeqId, outFrames, outMergedConfiguration,
- outSurfaceControl, outInsetsState, outActiveControls, outBundle,
- null /* outRelayoutResult */);
- }
-
- private int relayoutWindowInner(Session session, IWindow client, LayoutParams attrs,
- int requestedWidth, int requestedHeight, int viewVisibility, int flags, int seq,
- int lastSyncSeqId, ClientWindowFrames outFrames,
- MergedConfiguration outMergedConfiguration, SurfaceControl outSurfaceControl,
- InsetsState outInsetsState, InsetsSourceControl.Array outActiveControls,
- Bundle outBundle, WindowRelayoutResult outRelayoutResult) {
if (outActiveControls != null) {
outActiveControls.set(null, false /* copyControls */);
}
@@ -2649,14 +2624,8 @@
}
if (outFrames != null && outMergedConfiguration != null) {
- final boolean shouldReportActivityWindowInfo;
- if (Flags.windowSessionRelayoutInfo()) {
- shouldReportActivityWindowInfo = outRelayoutResult != null
+ final boolean shouldReportActivityWindowInfo = outRelayoutResult != null
&& win.mLastReportedActivityWindowInfo != null;
- } else {
- shouldReportActivityWindowInfo = outBundle != null
- && win.mLastReportedActivityWindowInfo != null;
- }
final ActivityWindowInfo outActivityWindowInfo = shouldReportActivityWindowInfo
? new ActivityWindowInfo()
: null;
@@ -2665,13 +2634,7 @@
outActivityWindowInfo, false /* useLatestConfig */, shouldRelayout);
if (shouldReportActivityWindowInfo) {
- if (Flags.windowSessionRelayoutInfo()) {
- outRelayoutResult.activityWindowInfo = outActivityWindowInfo;
- } else {
- outBundle.putParcelable(
- IWindowSession.KEY_RELAYOUT_BUNDLE_ACTIVITY_WINDOW_INFO,
- outActivityWindowInfo);
- }
+ outRelayoutResult.activityWindowInfo = outActivityWindowInfo;
}
// Set resize-handled here because the values are sent back to the client.
@@ -2702,28 +2665,16 @@
win.isVisible() /* visible */, false /* removed */);
}
- if (Flags.windowSessionRelayoutInfo()) {
- if (outRelayoutResult != null) {
- if (win.syncNextBuffer() && viewVisibility == View.VISIBLE
- && win.mSyncSeqId > lastSyncSeqId) {
- outRelayoutResult.syncSeqId = win.shouldSyncWithBuffers()
- ? win.mSyncSeqId
- : -1;
- win.markRedrawForSyncReported();
- } else {
- outRelayoutResult.syncSeqId = -1;
- }
- }
- } else if (outBundle != null) {
- final int maybeSyncSeqId;
+ if (outRelayoutResult != null) {
if (win.syncNextBuffer() && viewVisibility == View.VISIBLE
&& win.mSyncSeqId > lastSyncSeqId) {
- maybeSyncSeqId = win.shouldSyncWithBuffers() ? win.mSyncSeqId : -1;
+ outRelayoutResult.syncSeqId = win.shouldSyncWithBuffers()
+ ? win.mSyncSeqId
+ : -1;
win.markRedrawForSyncReported();
} else {
- maybeSyncSeqId = -1;
+ outRelayoutResult.syncSeqId = -1;
}
- outBundle.putInt(IWindowSession.KEY_RELAYOUT_BUNDLE_SEQID, maybeSyncSeqId);
}
if (configChanged) {
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index 022c6ce..d26df7a 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -612,10 +612,16 @@
mService.mTaskSupervisor.beginDeferResume();
boolean deferResume = true;
mService.mTaskSupervisor.setDeferRootVisibilityUpdate(true /* deferUpdate */);
- final boolean shouldDeferTransitionReady = transition != null && !t.isEmpty()
- && (transition.isCollecting() || Flags.alwaysDeferTransitionWhenApplyWct());
- if (shouldDeferTransitionReady) {
- transition.deferTransitionReady();
+ boolean deferTransitionReady = false;
+ if (transition != null && !t.isEmpty()) {
+ if (transition.isCollecting()) {
+ deferTransitionReady = true;
+ transition.deferTransitionReady();
+ } else if (Flags.alwaysDeferTransitionWhenApplyWct()) {
+ Slog.w(TAG, "Transition is not collecting when applyTransaction."
+ + " transition=" + transition + " state=" + transition.getState());
+ transition = null;
+ }
}
try {
final ArraySet<WindowContainer<?>> haveConfigChanges = new ArraySet<>();
@@ -771,7 +777,7 @@
mService.mWindowManager.mWindowPlacerLocked.requestTraversal();
}
} finally {
- if (shouldDeferTransitionReady) {
+ if (deferTransitionReady) {
transition.continueTransitionReady();
}
mService.mTaskSupervisor.setDeferRootVisibilityUpdate(false /* deferUpdate */);
diff --git a/services/core/lint-baseline.xml b/services/core/lint-baseline.xml
index 2ccd1e4..3b81f0a 100644
--- a/services/core/lint-baseline.xml
+++ b/services/core/lint-baseline.xml
@@ -145,4 +145,37 @@
line="7158"/>
</issue>
+ <issue
+ id="FlaggedApi"
+ message="Method `recordSmartReplied()` is a flagged API and should be inside an `if (Flags.lifetimeExtensionRefactor())` check (or annotate the surrounding method `onNotificationSmartReplySent` with `@FlaggedApi(Flags.FLAG_LIFETIME_EXTENSION_REFACTOR) to transfer requirement to caller`)"
+ errorLine1=" r.recordSmartReplied();"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/services/core/java/com/android/server/notification/NotificationManagerService.java"
+ line="1591"
+ column="21"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `getPackageImportanceWithIdentity()` is a flagged API and should be inside an `if (Flags.lifetimeExtensionRefactor())` check (or annotate the surrounding method `enqueueNotificationInternal` with `@FlaggedApi(Flags.FLAG_LIFETIME_EXTENSION_REFACTOR) to transfer requirement to caller`)"
+ errorLine1=" final int packageImportance = getPackageImportanceWithIdentity(pkg);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/services/core/java/com/android/server/notification/NotificationManagerService.java"
+ line="7546"
+ column="39"/>
+ </issue>
+
+ <issue
+ id="FlaggedApi"
+ message="Method `getPackageImportanceWithIdentity()` is a flagged API and should be inside an `if (Flags.lifetimeExtensionRefactor())` check (or annotate the surrounding method `onShortcutRemoved` with `@FlaggedApi(Flags.FLAG_LIFETIME_EXTENSION_REFACTOR) to transfer requirement to caller`)"
+ errorLine1=" final int packageImportance = getPackageImportanceWithIdentity(packageName);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/services/core/java/com/android/server/notification/NotificationManagerService.java"
+ line="7916"
+ column="51"/>
+ </issue>
+
</issues>
\ No newline at end of file
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 611a4eb..215cf2c 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -2644,9 +2644,13 @@
mSystemServiceManager.startService(MediaMetricsManagerService.class);
t.traceEnd();
- t.traceBegin("StartBackgroundInstallControlService");
- mSystemServiceManager.startService(BackgroundInstallControlService.class);
- t.traceEnd();
+ if (!com.android.server.flags.Flags.optionalBackgroundInstallControl()
+ || SystemProperties.getBoolean(
+ "ro.system_settings.service.backgound_install_control_enabled", true)) {
+ t.traceBegin("StartBackgroundInstallControlService");
+ mSystemServiceManager.startService(BackgroundInstallControlService.class);
+ t.traceEnd();
+ }
}
t.traceBegin("StartMediaProjectionManager");
diff --git a/services/tests/InputMethodSystemServerTests/Android.bp b/services/tests/InputMethodSystemServerTests/Android.bp
index 0da17e1..3bce9b5 100644
--- a/services/tests/InputMethodSystemServerTests/Android.bp
+++ b/services/tests/InputMethodSystemServerTests/Android.bp
@@ -84,7 +84,6 @@
],
srcs: [
"src/com/android/server/inputmethod/**/ClientControllerTest.java",
- "src/com/android/server/inputmethod/**/UserDataRepositoryTest.java",
],
auto_gen_config: true,
}
diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/UserDataRepositoryTest.java b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/UserDataRepositoryTest.java
index c3a87da..79943f6 100644
--- a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/UserDataRepositoryTest.java
+++ b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/UserDataRepositoryTest.java
@@ -30,6 +30,7 @@
import com.android.server.pm.UserManagerInternal;
+import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -63,6 +64,7 @@
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
+ SecureSettingsWrapper.startTestMode();
mHandler = new Handler(Looper.getMainLooper());
mBindingControllerFactory = new IntFunction<InputMethodBindingController>() {
@@ -73,6 +75,11 @@
};
}
+ @After
+ public void tearDown() {
+ SecureSettingsWrapper.endTestMode();
+ }
+
@Test
public void testUserDataRepository_addsNewUserInfoOnUserCreatedEvent() {
// Create UserDataRepository and capture the user lifecycle listener
diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/BrightnessClamperControllerTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/BrightnessClamperControllerTest.java
index 69043f5..e982153 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/BrightnessClamperControllerTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/BrightnessClamperControllerTest.java
@@ -16,19 +16,19 @@
package com.android.server.display.brightness.clamper;
+import static android.view.Display.STATE_OFF;
import static android.view.Display.STATE_ON;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
-import android.hardware.Sensor;
-import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.hardware.display.BrightnessInfo;
import android.hardware.display.DisplayManagerInternal;
@@ -40,12 +40,10 @@
import androidx.test.filters.SmallTest;
import androidx.test.platform.app.InstrumentationRegistry;
-import com.android.internal.util.test.FakeSettingsProvider;
-import com.android.internal.util.test.FakeSettingsProviderRule;
import com.android.server.display.DisplayBrightnessState;
import com.android.server.display.DisplayDeviceConfig;
-import com.android.server.display.TestUtils;
import com.android.server.display.brightness.BrightnessReason;
+import com.android.server.display.config.SensorData;
import com.android.server.display.feature.DeviceConfigParameterProvider;
import com.android.server.display.feature.DisplayManagerFlags;
import com.android.server.testutils.OffsettableClock;
@@ -63,6 +61,7 @@
@SmallTest
public class BrightnessClamperControllerTest {
private static final float FLOAT_TOLERANCE = 0.001f;
+ private static final int DISPLAY_ID = 2;
private final OffsettableClock mClock = new OffsettableClock();
private final TestHandler mTestHandler = new TestHandler(null, mClock);
@@ -78,8 +77,12 @@
@Mock
private BrightnessClamperController.DisplayDeviceData mMockDisplayDeviceData;
@Mock
+ private SensorData mMockSensorData;
+ @Mock
private DeviceConfigParameterProvider mMockDeviceConfigParameterProvider;
@Mock
+ private LightSensorController mMockLightSensorController;
+ @Mock
private BrightnessClamper<BrightnessClamperController.DisplayDeviceData> mMockClamper;
@Mock
private DisplayManagerFlags mFlags;
@@ -88,23 +91,17 @@
@Mock
private DisplayManagerInternal.DisplayPowerRequest mMockRequest;
- Sensor mLightSensor;
-
@Mock
private DeviceConfig.Properties mMockProperties;
private BrightnessClamperController mClamperController;
private TestInjector mTestInjector;
- @Rule
- public FakeSettingsProviderRule mSettingsProviderRule = FakeSettingsProvider.rule();
-
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
- mLightSensor = TestUtils.createSensor(Sensor.TYPE_LIGHT, "Light Sensor");
mTestInjector = new TestInjector(List.of(mMockClamper), List.of(mMockModifier));
- when(mSensorManager.getDefaultSensor(anyInt())).thenReturn(mLightSensor);
- when(mMockModifier.shouldListenToLightSensor()).thenReturn(true);
+ when(mMockDisplayDeviceData.getDisplayId()).thenReturn(DISPLAY_ID);
+ when(mMockDisplayDeviceData.getAmbientLightSensor()).thenReturn(mMockSensorData);
mClamperController = createBrightnessClamperController();
}
@@ -115,6 +112,25 @@
}
@Test
+ public void testConstructor_ConfiguresLightSensorController() {
+ verify(mMockLightSensorController).configure(mMockSensorData, DISPLAY_ID);
+ }
+
+ @Test
+ public void testConstructor_doesNotStartsLightSensorController() {
+ verify(mMockLightSensorController, never()).restart();
+ }
+
+ @Test
+ public void testConstructor_startsLightSensorController() {
+ when(mMockModifier.shouldListenToLightSensor()).thenReturn(true);
+
+ mClamperController = createBrightnessClamperController();
+
+ verify(mMockLightSensorController).restart();
+ }
+
+ @Test
public void testStop_RemovesOnPropertiesChangeListener() {
ArgumentCaptor<DeviceConfig.OnPropertiesChangedListener> captor = ArgumentCaptor.forClass(
DeviceConfig.OnPropertiesChangedListener.class);
@@ -152,6 +168,21 @@
}
@Test
+ public void testOnDisplayChanged_doesNotRestartLightSensor() {
+ mClamperController.onDisplayChanged(mMockDisplayDeviceData);
+
+ verify(mMockLightSensorController, never()).restart();
+ }
+
+ @Test
+ public void testOnDisplayChanged_restartsLightSensor() {
+ when(mMockModifier.shouldListenToLightSensor()).thenReturn(true);
+ mClamperController.onDisplayChanged(mMockDisplayDeviceData);
+
+ verify(mMockLightSensorController).restart();
+ }
+
+ @Test
public void testClamp_AppliesModifier() {
float initialBrightness = 0.2f;
boolean initialSlowChange = true;
@@ -161,6 +192,26 @@
}
@Test
+ public void testClamp_restartsLightSensor() {
+ float initialBrightness = 0.2f;
+ boolean initialSlowChange = true;
+ when(mMockModifier.shouldListenToLightSensor()).thenReturn(true);
+ mClamperController.clamp(mMockRequest, initialBrightness, initialSlowChange, STATE_ON);
+
+ verify(mMockLightSensorController).restart();
+ }
+
+ @Test
+ public void testClamp_stopsLightSensor() {
+ float initialBrightness = 0.2f;
+ boolean initialSlowChange = true;
+ clearInvocations(mMockLightSensorController);
+ mClamperController.clamp(mMockRequest, initialBrightness, initialSlowChange, STATE_OFF);
+
+ verify(mMockLightSensorController).stop();
+ }
+
+ @Test
public void testClamp_inactiveClamperNotApplied() {
float initialBrightness = 0.8f;
boolean initialSlowChange = true;
@@ -260,33 +311,17 @@
}
@Test
- public void testAmbientLuxChanges() throws Exception {
- ArgumentCaptor<SensorEventListener> listenerCaptor = ArgumentCaptor.forClass(
- SensorEventListener.class);
+ public void testAmbientLuxChanges() {
+ mTestInjector.mCapturedLightSensorListener.onAmbientLuxChange(50);
- verify(mSensorManager).registerListener(listenerCaptor.capture(), eq(mLightSensor),
- anyInt(), any(Handler.class));
- SensorEventListener listener = listenerCaptor.getValue();
-
- when(mSensorManager.getSensorList(eq(Sensor.TYPE_ALL))).thenReturn(List.of(mLightSensor));
-
- float initialBrightness = 0.8f;
- boolean initialSlowChange = true;
-
- DisplayBrightnessState state = mClamperController.clamp(mMockRequest, initialBrightness,
- initialSlowChange, STATE_ON);
- assertEquals(initialBrightness, state.getBrightness(), FLOAT_TOLERANCE);
-
- listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 50, mClock.now()));
verify(mMockModifier).setAmbientLux(50);
-
- listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 300, mClock.now()));
- verify(mMockModifier).setAmbientLux(300);
}
@Test
public void testStop() {
+ clearInvocations(mMockLightSensorController);
mClamperController.stop();
+ verify(mMockLightSensorController).stop();
verify(mMockModifier).stop();
verify(mMockClamper).stop();
}
@@ -303,6 +338,7 @@
private final List<BrightnessStateModifier> mModifiers;
private BrightnessClamperController.ClamperChangeListener mCapturedChangeListener;
+ private LightSensorController.LightSensorListener mCapturedLightSensorListener;
private TestInjector(
List<BrightnessClamper<? super BrightnessClamperController.DisplayDeviceData>>
@@ -330,8 +366,15 @@
@Override
List<BrightnessStateModifier> getModifiers(DisplayManagerFlags flags, Context context,
Handler handler, BrightnessClamperController.ClamperChangeListener listener,
- DisplayDeviceConfig displayDeviceConfig, SensorManager sensorManager) {
+ DisplayDeviceConfig displayDeviceConfig) {
return mModifiers;
}
+
+ @Override
+ LightSensorController getLightSensorController(SensorManager sensorManager, Context context,
+ LightSensorController.LightSensorListener listener, Handler handler) {
+ mCapturedLightSensorListener = listener;
+ return mMockLightSensorController;
+ }
}
}
diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/LightSensorControllerTest.kt b/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/LightSensorControllerTest.kt
new file mode 100644
index 0000000..b742d02
--- /dev/null
+++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/LightSensorControllerTest.kt
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display.brightness.clamper
+
+import android.content.res.Resources
+import android.hardware.Sensor
+import android.hardware.SensorEventListener
+import android.hardware.SensorManager
+import android.os.Handler
+import androidx.test.filters.SmallTest
+import com.android.server.display.TestUtils
+import com.android.server.display.brightness.clamper.LightSensorController.Injector
+import com.android.server.display.brightness.clamper.LightSensorController.LightSensorListener
+import com.android.server.display.config.SensorData
+import com.android.server.display.utils.AmbientFilter
+import org.junit.Before
+import org.mockito.kotlin.any
+import org.mockito.kotlin.argumentCaptor
+import org.mockito.kotlin.eq
+import org.mockito.kotlin.inOrder
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.verify
+import org.mockito.kotlin.verifyNoMoreInteractions
+import org.mockito.kotlin.whenever
+
+private const val LIGHT_SENSOR_RATE: Int = 10
+private const val DISPLAY_ID: Int = 3
+private const val NOW: Long = 3_000
+
+@SmallTest
+class LightSensorControllerTest {
+
+ private val mockSensorManager: SensorManager = mock()
+ private val mockResources: Resources = mock()
+ private val mockLightSensorListener: LightSensorListener = mock()
+ private val mockHandler: Handler = mock()
+ private val mockAmbientFilter: AmbientFilter = mock()
+
+ private val testInjector = TestInjector()
+ private val dummySensorData = SensorData()
+
+ private lateinit var controller: LightSensorController
+
+ @Before
+ fun setUp() {
+ controller = LightSensorController(mockSensorManager, mockResources,
+ mockLightSensorListener, mockHandler, testInjector)
+ }
+
+ fun `does not register light sensor if is not configured`() {
+ controller.restart()
+
+ verifyNoMoreInteractions(mockSensorManager, mockAmbientFilter, mockLightSensorListener)
+ }
+
+ fun `does not register light sensor if missing`() {
+ controller.configure(dummySensorData, DISPLAY_ID)
+ controller.restart()
+
+ verifyNoMoreInteractions(mockSensorManager, mockAmbientFilter, mockLightSensorListener)
+ }
+
+ fun `register light sensor if configured and present`() {
+ testInjector.lightSensor = TestUtils
+ .createSensor(Sensor.TYPE_LIGHT, Sensor.STRING_TYPE_LIGHT)
+ controller.configure(dummySensorData, DISPLAY_ID)
+ controller.restart()
+
+ verify(mockSensorManager).registerListener(any(),
+ testInjector.lightSensor, LIGHT_SENSOR_RATE * 1000, mockHandler)
+ verifyNoMoreInteractions(mockSensorManager, mockAmbientFilter, mockLightSensorListener)
+ }
+
+ fun `register light sensor once if not changed`() {
+ testInjector.lightSensor = TestUtils
+ .createSensor(Sensor.TYPE_LIGHT, Sensor.STRING_TYPE_LIGHT)
+ controller.configure(dummySensorData, DISPLAY_ID)
+
+ controller.restart()
+ controller.restart()
+
+ verify(mockSensorManager).registerListener(any(),
+ testInjector.lightSensor, LIGHT_SENSOR_RATE * 1000, mockHandler)
+ verifyNoMoreInteractions(mockSensorManager, mockAmbientFilter, mockLightSensorListener)
+ }
+
+ fun `register new light sensor and unregister old if changed`() {
+ val lightSensor1 = TestUtils
+ .createSensor(Sensor.TYPE_LIGHT, Sensor.STRING_TYPE_LIGHT)
+ testInjector.lightSensor = lightSensor1
+ controller.configure(dummySensorData, DISPLAY_ID)
+ controller.restart()
+
+ val lightSensor2 = TestUtils
+ .createSensor(Sensor.TYPE_LIGHT, Sensor.STRING_TYPE_LIGHT)
+ testInjector.lightSensor = lightSensor2
+ controller.configure(dummySensorData, DISPLAY_ID)
+ controller.restart()
+
+ inOrder {
+ verify(mockSensorManager).registerListener(any(),
+ lightSensor1, LIGHT_SENSOR_RATE * 1000, mockHandler)
+ verify(mockSensorManager).unregisterListener(any<SensorEventListener>())
+ verify(mockAmbientFilter).clear()
+ verify(mockLightSensorListener).onAmbientLuxChange(LightSensorController.INVALID_LUX)
+ verify(mockSensorManager).registerListener(any(),
+ lightSensor2, LIGHT_SENSOR_RATE * 1000, mockHandler)
+ }
+ verifyNoMoreInteractions(mockSensorManager, mockAmbientFilter, mockLightSensorListener)
+ }
+
+ fun `notifies listener on ambient lux change`() {
+ val expectedLux = 40f
+ val eventLux = 50
+ val eventTime = 60L
+ whenever(mockAmbientFilter.getEstimate(NOW)).thenReturn(expectedLux)
+ val listenerCaptor = argumentCaptor<SensorEventListener>()
+ testInjector.lightSensor = TestUtils
+ .createSensor(Sensor.TYPE_LIGHT, Sensor.STRING_TYPE_LIGHT)
+ controller.configure(dummySensorData, DISPLAY_ID)
+ controller.restart()
+ verify(mockSensorManager).registerListener(listenerCaptor.capture(),
+ eq(testInjector.lightSensor), eq(LIGHT_SENSOR_RATE * 1000), eq(mockHandler))
+
+ val listener = listenerCaptor.lastValue
+ listener.onSensorChanged(TestUtils.createSensorEvent(testInjector.lightSensor,
+ eventLux, eventTime * 1_000_000))
+
+ inOrder {
+ verify(mockAmbientFilter).addValue(eventTime, eventLux.toFloat())
+ verify(mockLightSensorListener).onAmbientLuxChange(expectedLux)
+ }
+ }
+
+ private inner class TestInjector : Injector() {
+ var lightSensor: Sensor? = null
+ override fun getLightSensor(sensorManager: SensorManager?,
+ sensorData: SensorData?, fallbackType: Int): Sensor? {
+ return lightSensor
+ }
+
+ override fun getLightSensorRate(resources: Resources?): Int {
+ return LIGHT_SENSOR_RATE
+ }
+
+ override fun getAmbientFilter(resources: Resources?): AmbientFilter {
+ return mockAmbientFilter
+ }
+
+ override fun getTime(): Long {
+ return NOW
+ }
+ }
+}
\ No newline at end of file
diff --git a/services/tests/dreamservicetests/src/com/android/server/dreams/TestDreamEnvironment.java b/services/tests/dreamservicetests/src/com/android/server/dreams/TestDreamEnvironment.java
index 3d03bf2..e2b93ae 100644
--- a/services/tests/dreamservicetests/src/com/android/server/dreams/TestDreamEnvironment.java
+++ b/services/tests/dreamservicetests/src/com/android/server/dreams/TestDreamEnvironment.java
@@ -205,7 +205,7 @@
@Override
public DreamOverlayConnectionHandler createOverlayConnection(
- ComponentName overlayComponent) {
+ ComponentName overlayComponent, Runnable onDisconnected) {
return mDreamOverlayConnectionHandler;
}
diff --git a/services/tests/mockingservicestests/src/android/service/dreams/DreamOverlayConnectionHandlerTest.java b/services/tests/mockingservicestests/src/android/service/dreams/DreamOverlayConnectionHandlerTest.java
index 22d7e73..3e65585 100644
--- a/services/tests/mockingservicestests/src/android/service/dreams/DreamOverlayConnectionHandlerTest.java
+++ b/services/tests/mockingservicestests/src/android/service/dreams/DreamOverlayConnectionHandlerTest.java
@@ -49,10 +49,6 @@
@SmallTest
@RunWith(AndroidJUnit4.class)
public class DreamOverlayConnectionHandlerTest {
- private static final int MIN_CONNECTION_DURATION_MS = 100;
- private static final int MAX_RECONNECT_ATTEMPTS = 3;
- private static final int BASE_RECONNECT_DELAY_MS = 50;
-
@Mock
private Context mContext;
@Mock
@@ -63,6 +59,8 @@
private IDreamOverlay mOverlayService;
@Mock
private IDreamOverlayClient mOverlayClient;
+ @Mock
+ private Runnable mOnDisconnectRunnable;
private TestLooper mTestLooper;
private DreamOverlayConnectionHandler mDreamOverlayConnectionHandler;
@@ -75,9 +73,7 @@
mContext,
mTestLooper.getLooper(),
mServiceIntent,
- MIN_CONNECTION_DURATION_MS,
- MAX_RECONNECT_ATTEMPTS,
- BASE_RECONNECT_DELAY_MS,
+ mOnDisconnectRunnable,
new TestInjector(mConnection));
}
@@ -119,12 +115,14 @@
mTestLooper.dispatchAll();
// No client yet, so we shouldn't have executed
verify(consumer, never()).accept(mOverlayClient);
+ verify(mOnDisconnectRunnable, never()).run();
provideClient();
// Service disconnected before looper could handle the message.
disconnectService();
mTestLooper.dispatchAll();
verify(consumer, never()).accept(mOverlayClient);
+ verify(mOnDisconnectRunnable).run();
}
@Test
@@ -237,8 +235,7 @@
@Override
public PersistentServiceConnection<IDreamOverlay> buildConnection(Context context,
- Handler handler, Intent serviceIntent, int minConnectionDurationMs,
- int maxReconnectAttempts, int baseReconnectDelayMs) {
+ Handler handler, Intent serviceIntent) {
return mConnection;
}
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/alarm/UserWakeupStoreTest.java b/services/tests/mockingservicestests/src/com/android/server/alarm/UserWakeupStoreTest.java
index 75e8e68..72883e2 100644
--- a/services/tests/mockingservicestests/src/com/android/server/alarm/UserWakeupStoreTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/alarm/UserWakeupStoreTest.java
@@ -134,6 +134,18 @@
}
@Test
+ public void testOnUserStarting_userIsRemovedFromTheStore() {
+ mUserWakeupStore.addUserWakeup(USER_ID_1, TEST_TIMESTAMP - 19_000);
+ mUserWakeupStore.addUserWakeup(USER_ID_2, TEST_TIMESTAMP - 7_000);
+ mUserWakeupStore.addUserWakeup(USER_ID_3, TEST_TIMESTAMP - 13_000);
+ assertEquals(3, mUserWakeupStore.getUserIdsToWakeup(TEST_TIMESTAMP).length);
+ mUserWakeupStore.onUserStarting(USER_ID_3);
+ // getWakeupTimeForUser returns negative wakeup time if there is no entry for user.
+ assertEquals(-1, mUserWakeupStore.getWakeupTimeForUser(USER_ID_3));
+ assertEquals(2, mUserWakeupStore.getUserIdsToWakeup(TEST_TIMESTAMP).length);
+ }
+
+ @Test
public void testGetNextUserWakeup() {
mUserWakeupStore.addUserWakeup(USER_ID_1, TEST_TIMESTAMP - 19_000);
mUserWakeupStore.addUserWakeup(USER_ID_2, TEST_TIMESTAMP - 3_000);
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java b/services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java
index e15942b..adcbf5c 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java
@@ -84,7 +84,11 @@
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
import java.util.Random;
+import java.util.function.Function;
import java.util.zip.GZIPInputStream;
/**
@@ -940,6 +944,228 @@
}
}
+ private ApplicationExitInfo createExitInfo(int i) {
+ ApplicationExitInfo info = new ApplicationExitInfo();
+ info.setPid(i);
+ info.setTimestamp(1000 + i);
+ info.setPackageUid(2000);
+ return info;
+ }
+
+ @SuppressWarnings("GuardedBy")
+ private ArrayList<ApplicationExitInfo> getExitInfosHelper(
+ AppExitInfoTracker.AppExitInfoContainer container, int filterPid, int maxNum) {
+ ArrayList<ApplicationExitInfo> infos = new ArrayList<ApplicationExitInfo>();
+ container.getExitInfosLocked(filterPid, maxNum, infos);
+ return infos;
+ }
+
+ @SuppressWarnings("GuardedBy")
+ private void checkAreHelper(AppExitInfoTracker.AppExitInfoContainer container, int filterPid,
+ int maxNum, List<Integer> expected, Function<ApplicationExitInfo, Integer> func) {
+ ArrayList<Integer> values = new ArrayList<Integer>();
+ getExitInfosHelper(container, filterPid, maxNum)
+ .forEach((exitInfo) -> values.add(func.apply(exitInfo)));
+ assertEquals(values, expected);
+
+ HashMap<Integer, Integer> expectedMultiset = new HashMap<Integer, Integer>();
+ expected.forEach(
+ (elem) -> expectedMultiset.put(elem, expectedMultiset.getOrDefault(elem, 0) + 1));
+ // `maxNum` isn't a parameter supported by `forEachRecordLocked()s`, but we can emulate it
+ // by stopping iteration when we've seen enough elements.
+ int[] numElementsToObserveWrapped = {maxNum};
+ container.forEachRecordLocked((exitInfo) -> {
+ // Same thing as above, `filterPid` isn't a parameter supported out of the box for
+ // `forEachRecordLocked()`, but we emulate it here.
+ if (filterPid > 0 && filterPid != exitInfo.getPid()) {
+ return AppExitInfoTracker.FOREACH_ACTION_NONE;
+ }
+
+ Integer key = func.apply(exitInfo);
+ assertTrue(expectedMultiset.toString(), expectedMultiset.containsKey(key));
+ Integer references = expectedMultiset.get(key);
+ if (references == 1) {
+ expectedMultiset.remove(key);
+ } else {
+ expectedMultiset.put(key, references - 1);
+ }
+ if (--numElementsToObserveWrapped[0] == 0) {
+ return AppExitInfoTracker.FOREACH_ACTION_STOP_ITERATION;
+ }
+ return AppExitInfoTracker.FOREACH_ACTION_NONE;
+ });
+ assertEquals(expectedMultiset.size(), 0);
+ }
+
+ private void checkPidsAre(AppExitInfoTracker.AppExitInfoContainer container, int filterPid,
+ int maxNum, List<Integer> expectedPids) {
+ checkAreHelper(container, filterPid, maxNum, expectedPids, (exitInfo) -> exitInfo.getPid());
+ }
+
+ private void checkPidsAre(
+ AppExitInfoTracker.AppExitInfoContainer container, List<Integer> expectedPids) {
+ checkPidsAre(container, 0, 0, expectedPids);
+ }
+
+ private void checkTimestampsAre(AppExitInfoTracker.AppExitInfoContainer container,
+ int filterPid, int maxNum, List<Integer> expectedTimestamps) {
+ checkAreHelper(container, filterPid, maxNum, expectedTimestamps,
+ (exitInfo) -> (int) exitInfo.getTimestamp());
+ }
+
+ private void checkTimestampsAre(
+ AppExitInfoTracker.AppExitInfoContainer container, List<Integer> expectedTimestamps) {
+ checkTimestampsAre(container, 0, 0, expectedTimestamps);
+ }
+
+ @SuppressWarnings("GuardedBy")
+ private AppExitInfoTracker.AppExitInfoContainer createBasicContainer() {
+ AppExitInfoTracker.AppExitInfoContainer container =
+ mAppExitInfoTracker.new AppExitInfoContainer(3);
+ container.addExitInfoLocked(createExitInfo(10));
+ container.addExitInfoLocked(createExitInfo(30));
+ container.addExitInfoLocked(createExitInfo(20));
+ return container;
+ }
+
+ @Test
+ @SuppressWarnings("GuardedBy")
+ public void testContainerGetExitInfosIsSortedNewestFirst() throws Exception {
+ AppExitInfoTracker.AppExitInfoContainer container = createBasicContainer();
+ checkPidsAre(container, Arrays.asList(30, 20, 10));
+ }
+
+ @Test
+ @SuppressWarnings("GuardedBy")
+ public void testContainerRemovesOldestReports() throws Exception {
+ AppExitInfoTracker.AppExitInfoContainer container = createBasicContainer();
+ container.addExitInfoLocked(createExitInfo(40));
+ checkPidsAre(container, Arrays.asList(40, 30, 20));
+
+ container.addExitInfoLocked(createExitInfo(50));
+ checkPidsAre(container, Arrays.asList(50, 40, 30));
+
+ container.addExitInfoLocked(createExitInfo(45));
+ checkPidsAre(container, Arrays.asList(50, 45, 40));
+
+ // Adding an older report shouldn't remove the newer ones.
+ container.addExitInfoLocked(createExitInfo(15));
+ checkPidsAre(container, Arrays.asList(50, 45, 40));
+ }
+
+ @Test
+ @SuppressWarnings("GuardedBy")
+ public void testContainerFilterByPid() throws Exception {
+ AppExitInfoTracker.AppExitInfoContainer container = createBasicContainer();
+ assertEquals(1, getExitInfosHelper(container, 30, 0).size());
+ assertEquals(30, getExitInfosHelper(container, 0, 0).get(0).getPid());
+
+ assertEquals(1, getExitInfosHelper(container, 30, 0).size());
+ assertEquals(20, getExitInfosHelper(container, 20, 0).get(0).getPid());
+
+ assertEquals(1, getExitInfosHelper(container, 10, 0).size());
+ assertEquals(10, getExitInfosHelper(container, 10, 0).get(0).getPid());
+
+ assertEquals(0, getExitInfosHelper(container, 1337, 0).size());
+ }
+
+ @Test
+ @SuppressWarnings("GuardedBy")
+ public void testContainerLimitQuantityOfResults() throws Exception {
+ AppExitInfoTracker.AppExitInfoContainer container = createBasicContainer();
+ checkPidsAre(container, /* filterPid */ 30, /* maxNum */ 1, Arrays.asList(30));
+ checkPidsAre(container, /* filterPid */ 30, /* maxNum */ 1000, Arrays.asList(30));
+
+ checkPidsAre(container, /* filterPid */ 20, /* maxNum */ 1, Arrays.asList(20));
+ checkPidsAre(container, /* filterPid */ 20, /* maxNum */ 1000, Arrays.asList(20));
+
+ checkPidsAre(container, /* filterPid */ 10, /* maxNum */ 1, Arrays.asList(10));
+ checkPidsAre(container, /* filterPid */ 10, /* maxNum */ 1000, Arrays.asList(10));
+
+ checkPidsAre(container, /* filterPid */ 1337, /* maxNum */ 1, Arrays.asList());
+ checkPidsAre(container, /* filterPid */ 1337, /* maxNum */ 1000, Arrays.asList());
+ }
+
+ @Test
+ @SuppressWarnings("GuardedBy")
+ public void testContainerLastExitInfoForPid() throws Exception {
+ AppExitInfoTracker.AppExitInfoContainer container = createBasicContainer();
+ assertEquals(30, container.getLastExitInfoForPid(30).getPid());
+ assertEquals(20, container.getLastExitInfoForPid(20).getPid());
+ assertEquals(10, container.getLastExitInfoForPid(10).getPid());
+ assertEquals(null, container.getLastExitInfoForPid(1337));
+ }
+
+ @Test
+ @SuppressWarnings("GuardedBy")
+ public void testContainerCanHoldMultipleFromSamePid() throws Exception {
+ AppExitInfoTracker.AppExitInfoContainer container = createBasicContainer();
+ ApplicationExitInfo info = createExitInfo(100);
+ ApplicationExitInfo info2 = createExitInfo(100);
+ ApplicationExitInfo info3 = createExitInfo(100);
+ info2.setTimestamp(1337);
+ info3.setTimestamp(31337);
+
+ container.addExitInfoLocked(info);
+ assertEquals(1100, container.getLastExitInfoForPid(100).getTimestamp());
+ container.addExitInfoLocked(info2);
+ assertEquals(1337, container.getLastExitInfoForPid(100).getTimestamp());
+ container.addExitInfoLocked(info3);
+ assertEquals(31337, container.getLastExitInfoForPid(100).getTimestamp());
+
+ checkPidsAre(container, Arrays.asList(100, 100, 100));
+ checkTimestampsAre(container, Arrays.asList(31337, 1337, 1100));
+
+ checkPidsAre(container, /* filterPid */ 100, /* maxNum */ 0, Arrays.asList(100, 100, 100));
+ checkTimestampsAre(
+ container, /* filterPid */ 100, /* maxNum */ 0, Arrays.asList(31337, 1337, 1100));
+
+ checkPidsAre(container, /* filterPid */ 100, /* maxNum */ 2, Arrays.asList(100, 100));
+ checkTimestampsAre(
+ container, /* filterPid */ 100, /* maxNum */ 2, Arrays.asList(31337, 1337));
+ }
+
+ @Test
+ @SuppressWarnings("GuardedBy")
+ public void testContainerIteration() throws Exception {
+ AppExitInfoTracker.AppExitInfoContainer container = createBasicContainer();
+ checkPidsAre(container, Arrays.asList(30, 20, 10));
+
+ // Unfortunately relying on order for this test, which is implemented as "last inserted" ->
+ // "first inserted". Note that this is insertion order, not timestamp. Thus, it's 20 -> 30
+ // -> 10, as defined by `createBasicContainer()`.
+ List<Integer> elements = Arrays.asList(20, 30, 10);
+ for (int i = 0, size = elements.size(); i < size; i++) {
+ ArrayList<Integer> processedEntries = new ArrayList<Integer>();
+ final int finalIndex = i;
+ container.forEachRecordLocked((exitInfo) -> {
+ processedEntries.add(new Integer(exitInfo.getPid()));
+ if (exitInfo.getPid() == elements.get(finalIndex)) {
+ return AppExitInfoTracker.FOREACH_ACTION_STOP_ITERATION;
+ }
+ return AppExitInfoTracker.FOREACH_ACTION_NONE;
+ });
+ assertEquals(processedEntries, elements.subList(0, i + 1));
+ }
+ }
+
+ @Test
+ @SuppressWarnings("GuardedBy")
+ public void testContainerIterationRemove() throws Exception {
+ for (int pidToRemove : Arrays.asList(30, 20, 10)) {
+ AppExitInfoTracker.AppExitInfoContainer container = createBasicContainer();
+ container.forEachRecordLocked((exitInfo) -> {
+ if (exitInfo.getPid() == pidToRemove) {
+ return AppExitInfoTracker.FOREACH_ACTION_REMOVE_ITEM;
+ }
+ return AppExitInfoTracker.FOREACH_ACTION_NONE;
+ });
+ ArrayList<Integer> pidsRemaining = new ArrayList<Integer>(Arrays.asList(30, 20, 10));
+ pidsRemaining.remove(new Integer(pidToRemove));
+ checkPidsAre(container, pidsRemaining);
+ }
+ }
+
private static int makeExitStatus(int exitCode) {
return (exitCode << 8) & 0xff00;
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/trust/TrustManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/trust/TrustManagerServiceTest.java
index 2a67029..7aec42b 100644
--- a/services/tests/mockingservicestests/src/com/android/server/trust/TrustManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/trust/TrustManagerServiceTest.java
@@ -72,9 +72,6 @@
import android.os.ServiceManager;
import android.os.UserHandle;
import android.os.UserManager;
-import android.platform.test.annotations.RequiresFlagsEnabled;
-import android.platform.test.flag.junit.CheckFlagsRule;
-import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.provider.Settings;
import android.security.KeyStoreAuthorization;
import android.service.trust.GrantTrustResult;
@@ -124,9 +121,6 @@
.build();
@Rule
- public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
-
- @Rule
public final MockContext mMockContext = new MockContext(
ApplicationProvider.getApplicationContext());
@@ -418,7 +412,6 @@
// user, not the profile. This matches the authentication that is needed to unlock the device
// for the profile again.
@Test
- @RequiresFlagsEnabled(android.security.Flags.FLAG_FIX_UNLOCKED_DEVICE_REQUIRED_KEYS_V2)
public void testLockDeviceForManagedProfileWithUnifiedChallenge_usesParentBiometricSids()
throws Exception {
setupMocksForProfile(/* unifiedChallenge= */ true);
@@ -617,7 +610,6 @@
}
@Test
- @RequiresFlagsEnabled(android.security.Flags.FLAG_FIX_UNLOCKED_DEVICE_REQUIRED_KEYS_V2)
public void testKeystoreWeakUnlockEnabled_whenWeakFingerprintIsSetupAndAllowed()
throws Exception {
setupStrongAuthTrackerToAllowEverything();
@@ -626,7 +618,6 @@
}
@Test
- @RequiresFlagsEnabled(android.security.Flags.FLAG_FIX_UNLOCKED_DEVICE_REQUIRED_KEYS_V2)
public void testKeystoreWeakUnlockEnabled_whenWeakFaceIsSetupAndAllowed() throws Exception {
setupStrongAuthTrackerToAllowEverything();
setupFace(SensorProperties.STRENGTH_WEAK);
@@ -634,7 +625,6 @@
}
@Test
- @RequiresFlagsEnabled(android.security.Flags.FLAG_FIX_UNLOCKED_DEVICE_REQUIRED_KEYS_V2)
public void testKeystoreWeakUnlockEnabled_whenConvenienceFingerprintIsSetupAndAllowed()
throws Exception {
setupStrongAuthTrackerToAllowEverything();
@@ -643,7 +633,6 @@
}
@Test
- @RequiresFlagsEnabled(android.security.Flags.FLAG_FIX_UNLOCKED_DEVICE_REQUIRED_KEYS_V2)
public void testKeystoreWeakUnlockEnabled_whenConvenienceFaceIsSetupAndAllowed()
throws Exception {
setupStrongAuthTrackerToAllowEverything();
@@ -652,7 +641,6 @@
}
@Test
- @RequiresFlagsEnabled(android.security.Flags.FLAG_FIX_UNLOCKED_DEVICE_REQUIRED_KEYS_V2)
public void testKeystoreWeakUnlockDisabled_whenStrongAuthRequired() throws Exception {
setupStrongAuthTracker(StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN, true);
setupFace(SensorProperties.STRENGTH_WEAK);
@@ -660,7 +648,6 @@
}
@Test
- @RequiresFlagsEnabled(android.security.Flags.FLAG_FIX_UNLOCKED_DEVICE_REQUIRED_KEYS_V2)
public void testKeystoreWeakUnlockDisabled_whenNonStrongBiometricNotAllowed() throws Exception {
setupStrongAuthTracker(StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED,
/* isNonStrongBiometricAllowed= */ false);
@@ -669,7 +656,6 @@
}
@Test
- @RequiresFlagsEnabled(android.security.Flags.FLAG_FIX_UNLOCKED_DEVICE_REQUIRED_KEYS_V2)
public void testKeystoreWeakUnlockDisabled_whenWeakFingerprintSensorIsPresentButNotEnrolled()
throws Exception {
setupStrongAuthTrackerToAllowEverything();
@@ -678,7 +664,6 @@
}
@Test
- @RequiresFlagsEnabled(android.security.Flags.FLAG_FIX_UNLOCKED_DEVICE_REQUIRED_KEYS_V2)
public void testKeystoreWeakUnlockDisabled_whenWeakFaceSensorIsPresentButNotEnrolled()
throws Exception {
setupStrongAuthTrackerToAllowEverything();
@@ -687,7 +672,6 @@
}
@Test
- @RequiresFlagsEnabled(android.security.Flags.FLAG_FIX_UNLOCKED_DEVICE_REQUIRED_KEYS_V2)
public void
testKeystoreWeakUnlockDisabled_whenWeakFingerprintIsSetupButForbiddenByDevicePolicy()
throws Exception {
@@ -699,7 +683,6 @@
}
@Test
- @RequiresFlagsEnabled(android.security.Flags.FLAG_FIX_UNLOCKED_DEVICE_REQUIRED_KEYS_V2)
public void testKeystoreWeakUnlockDisabled_whenWeakFaceIsSetupButForbiddenByDevicePolicy()
throws Exception {
setupStrongAuthTrackerToAllowEverything();
@@ -710,7 +693,6 @@
}
@Test
- @RequiresFlagsEnabled(android.security.Flags.FLAG_FIX_UNLOCKED_DEVICE_REQUIRED_KEYS_V2)
public void testKeystoreWeakUnlockDisabled_whenOnlyStrongFingerprintIsSetup() throws Exception {
setupStrongAuthTrackerToAllowEverything();
setupFingerprint(SensorProperties.STRENGTH_STRONG);
@@ -718,7 +700,6 @@
}
@Test
- @RequiresFlagsEnabled(android.security.Flags.FLAG_FIX_UNLOCKED_DEVICE_REQUIRED_KEYS_V2)
public void testKeystoreWeakUnlockDisabled_whenOnlyStrongFaceIsSetup() throws Exception {
setupStrongAuthTrackerToAllowEverything();
setupFace(SensorProperties.STRENGTH_STRONG);
@@ -726,7 +707,6 @@
}
@Test
- @RequiresFlagsEnabled(android.security.Flags.FLAG_FIX_UNLOCKED_DEVICE_REQUIRED_KEYS_V2)
public void testKeystoreWeakUnlockDisabled_whenNoBiometricsAreSetup() throws Exception {
setupStrongAuthTrackerToAllowEverything();
verifyWeakUnlockDisabled();
diff --git a/services/tests/powerservicetests/src/com/android/server/power/ShutdownThreadTest.java b/services/tests/powerservicetests/src/com/android/server/power/ShutdownThreadTest.java
index 62075b8..ab1b0cc 100644
--- a/services/tests/powerservicetests/src/com/android/server/power/ShutdownThreadTest.java
+++ b/services/tests/powerservicetests/src/com/android/server/power/ShutdownThreadTest.java
@@ -17,11 +17,10 @@
package com.android.server.power;
import static com.android.server.power.ShutdownThread.DEFAULT_SHUTDOWN_VIBRATE_MS;
+
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -42,7 +41,6 @@
import java.io.File;
import java.io.FileOutputStream;
-import java.io.IOException;
/**
* Tests for {@link com.android.server.power.ShutdownThread}
@@ -88,6 +86,7 @@
@Mock private VibratorInfo mVibratorInfoMock;
private String mDefaultShutdownVibrationFilePath;
+ private boolean mShutdownVibrationDisabled;
private long mLastSleepDurationMs;
private ShutdownThread mShutdownThread;
@@ -168,6 +167,17 @@
.vibrate(any(VibrationEffect.class), any(VibrationAttributes.class));
}
+ @Test
+ public void testVibrationDisabled() throws Exception {
+ setShutdownVibrationFileContent(CLICK_VIB_SERIALIZATION);
+ mShutdownVibrationDisabled = true;
+
+ mShutdownThread.playShutdownVibration(mContextMock);
+
+ verify(mVibratorMock, never())
+ .vibrate(any(VibrationEffect.class), any(VibrationAttributes.class));
+ }
+
private void assertShutdownVibration(VibrationEffect effect, long vibrationSleepDuration)
throws Exception {
verify(mVibratorMock).vibrate(
@@ -214,5 +224,10 @@
public void sleep(long durationMs) {
mLastSleepDurationMs = durationMs;
}
+
+ @Override
+ public boolean isShutdownVibrationDisabled(Context context) {
+ return mShutdownVibrationDisabled;
+ }
}
}
diff --git a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
index 30e3b18..dbab54b 100644
--- a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
@@ -672,6 +672,61 @@
new HashSet<>(mUserController.getRunningUsersLU()));
}
+ /** Test scheduling stopping of background users - reschedule if current user is a guest. */
+ @Test
+ public void testScheduleStopOfBackgroundUser_rescheduleWhenGuest() throws Exception {
+ mSetFlagsRule.enableFlags(android.multiuser.Flags.FLAG_SCHEDULE_STOP_OF_BACKGROUND_USER);
+
+ mUserController.setInitialConfig(/* userSwitchUiEnabled= */ true,
+ /* maxRunningUsers= */ 10, /* delayUserDataLocking= */ false,
+ /* backgroundUserScheduledStopTimeSecs= */ 2);
+
+ final int TEST_USER_GUEST = 902;
+ setUpUser(TEST_USER_GUEST, UserInfo.FLAG_GUEST);
+
+ setUpUser(TEST_USER_ID2, NO_USERINFO_FLAGS);
+
+ // Switch to TEST_USER_ID from user 0
+ int numberOfUserSwitches = 0;
+ addForegroundUserAndContinueUserSwitch(TEST_USER_ID, UserHandle.USER_SYSTEM,
+ ++numberOfUserSwitches, false,
+ /* expectScheduleBackgroundUserStopping= */ false);
+ assertEquals(Arrays.asList(SYSTEM_USER_ID, TEST_USER_ID),
+ mUserController.getRunningUsersLU());
+
+ // Switch to TEST_USER_GUEST from TEST_USER_ID
+ addForegroundUserAndContinueUserSwitch(TEST_USER_GUEST, TEST_USER_ID,
+ ++numberOfUserSwitches, false,
+ /* expectScheduleBackgroundUserStopping= */ true);
+ assertEquals(Arrays.asList(SYSTEM_USER_ID, TEST_USER_ID, TEST_USER_GUEST),
+ mUserController.getRunningUsersLU());
+
+ // Allow the post-switch processing to complete.
+ // TEST_USER_ID may be scheduled for stopping, but it shouldn't actually stop since the
+ // current user is a Guest.
+ assertAndProcessScheduledStopBackgroundUser(true, TEST_USER_ID);
+ assertAndProcessScheduledStopBackgroundUser(false, TEST_USER_GUEST);
+ assertEquals(Arrays.asList(SYSTEM_USER_ID, TEST_USER_ID, TEST_USER_GUEST),
+ mUserController.getRunningUsersLU());
+
+ // Switch to TEST_USER_ID2 from TEST_USER_GUEST
+ // Guests are automatically stopped in the background, so it won't be scheduled.
+ addForegroundUserAndContinueUserSwitch(TEST_USER_ID2, TEST_USER_GUEST,
+ ++numberOfUserSwitches, true,
+ /* expectScheduleBackgroundUserStopping= */ false);
+ assertEquals(Arrays.asList(SYSTEM_USER_ID, TEST_USER_ID, TEST_USER_ID2),
+ mUserController.getRunningUsersLU());
+
+ // Allow the post-switch processing to complete.
+ // TEST_USER_ID should *still* be scheduled for stopping, since we skipped stopping it
+ // earlier.
+ assertAndProcessScheduledStopBackgroundUser(true, TEST_USER_ID);
+ assertAndProcessScheduledStopBackgroundUser(false, TEST_USER_GUEST);
+ assertAndProcessScheduledStopBackgroundUser(false, TEST_USER_ID2);
+ assertEquals(Arrays.asList(SYSTEM_USER_ID, TEST_USER_ID2),
+ mUserController.getRunningUsersLU());
+ }
+
/**
* Process queued SCHEDULED_STOP_BACKGROUND_USER_MSG message, if expected.
* @param userId the user we are checking to see whether it is scheduled.
@@ -682,11 +737,11 @@
boolean expectScheduled, @Nullable Integer userId) {
TestHandler handler = mInjector.mHandler;
if (expectScheduled) {
- assertTrue(handler.hasMessages(SCHEDULED_STOP_BACKGROUND_USER_MSG, userId));
+ assertTrue(handler.hasEqualMessages(SCHEDULED_STOP_BACKGROUND_USER_MSG, userId));
handler.removeMessages(SCHEDULED_STOP_BACKGROUND_USER_MSG, userId);
mUserController.processScheduledStopOfBackgroundUser(userId);
} else {
- assertFalse(handler.hasMessages(SCHEDULED_STOP_BACKGROUND_USER_MSG, userId));
+ assertFalse(handler.hasEqualMessages(SCHEDULED_STOP_BACKGROUND_USER_MSG, userId));
}
}
@@ -1534,9 +1589,9 @@
mInjector.mHandler.clearAllRecordedMessages();
// Verify that continueUserSwitch worked as expected
continueAndCompleteUserSwitch(userState, oldUserId, newUserId);
- assertEquals(mInjector.mHandler
- .hasMessages(SCHEDULED_STOP_BACKGROUND_USER_MSG, expectedOldUserId),
- expectScheduleBackgroundUserStopping);
+ assertEquals(expectScheduleBackgroundUserStopping,
+ mInjector.mHandler
+ .hasEqualMessages(SCHEDULED_STOP_BACKGROUND_USER_MSG, expectedOldUserId));
verify(mInjector, times(expectedNumberOfCalls)).dismissUserSwitchingDialog(any());
continueUserSwitchAssertions(oldUserId, newUserId, expectOldUserStopping,
expectScheduleBackgroundUserStopping);
@@ -1810,6 +1865,13 @@
}
private static class TestHandler extends Handler {
+ /**
+ * Keeps an accessible copy of messages that were queued for us to query.
+ *
+ * WARNING: queued messages get added to this, but processed/removed messages to NOT
+ * automatically get removed. This can lead to confusing bugs. Maybe one day someone will
+ * fix this, but in the meantime, this is your warning.
+ */
private final List<Message> mMessages = new ArrayList<>();
TestHandler(Looper looper) {
diff --git a/services/tests/servicestests/src/com/android/server/appwidget/AppWidgetServiceImplTest.java b/services/tests/servicestests/src/com/android/server/appwidget/AppWidgetServiceImplTest.java
index 8a7815e..c34e28f 100644
--- a/services/tests/servicestests/src/com/android/server/appwidget/AppWidgetServiceImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/appwidget/AppWidgetServiceImplTest.java
@@ -47,7 +47,9 @@
import android.os.Handler;
import android.os.UserHandle;
import android.test.InstrumentationTestCase;
+import android.util.ArraySet;
import android.util.AtomicFile;
+import android.util.SparseArray;
import android.util.Xml;
import android.widget.RemoteViews;
@@ -67,10 +69,12 @@
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import java.util.Random;
+import java.util.Set;
import java.util.concurrent.CountDownLatch;
/**
@@ -388,6 +392,93 @@
assertThat(target.previewLayout).isEqualTo(original.previewLayout);
}
+ public void testBackupRestoreControllerStatePersistence() throws IOException {
+ // Setup mock data
+ final Set<String> mockPrunedApps = getMockPrunedApps();
+ final SparseArray<
+ List<AppWidgetServiceImpl.BackupRestoreController.RestoreUpdateRecord>
+ > mockUpdatesByProvider = getMockUpdates();
+ final SparseArray<
+ List<AppWidgetServiceImpl.BackupRestoreController.RestoreUpdateRecord>
+ > mockUpdatesByHost = getMockUpdates();
+ final AppWidgetServiceImpl.BackupRestoreController.State state =
+ new AppWidgetServiceImpl.BackupRestoreController.State(
+ mockPrunedApps, mockUpdatesByProvider, mockUpdatesByHost);
+
+ final File file = new File(mTestContext.getDataDir(), "state.xml");
+ saveBackupRestoreControllerState(file, state);
+ final AppWidgetServiceImpl.BackupRestoreController.State target =
+ loadStateLocked(file);
+ assertNotNull(target);
+ final SparseArray<List<AppWidgetServiceImpl.BackupRestoreController.RestoreUpdateRecord>>
+ actualUpdatesByProvider = target.getUpdatesByProvider();
+ assertNotNull(actualUpdatesByProvider);
+ final SparseArray<List<AppWidgetServiceImpl.BackupRestoreController.RestoreUpdateRecord>>
+ actualUpdatesByHost = target.getUpdatesByHost();
+ assertNotNull(actualUpdatesByHost);
+
+ assertEquals(mockPrunedApps, target.getPrunedApps());
+ for (int i = 0; i < mockUpdatesByProvider.size(); i++) {
+ final int key = mockUpdatesByProvider.keyAt(i);
+ verifyRestoreUpdateRecord(
+ actualUpdatesByProvider.get(key), mockUpdatesByProvider.get(key));
+ }
+ for (int i = 0; i < mockUpdatesByHost.size(); i++) {
+ final int key = mockUpdatesByHost.keyAt(i);
+ verifyRestoreUpdateRecord(
+ actualUpdatesByHost.get(key), mockUpdatesByHost.get(key));
+ }
+ }
+
+ private void verifyRestoreUpdateRecord(
+ @NonNull final List<AppWidgetServiceImpl.BackupRestoreController.RestoreUpdateRecord>
+ actualUpdates,
+ @NonNull final List<AppWidgetServiceImpl.BackupRestoreController.RestoreUpdateRecord>
+ expectedUpdates) {
+ assertEquals(expectedUpdates.size(), actualUpdates.size());
+ for (int i = 0; i < expectedUpdates.size(); i++) {
+ final AppWidgetServiceImpl.BackupRestoreController.RestoreUpdateRecord expected =
+ expectedUpdates.get(i);
+ final AppWidgetServiceImpl.BackupRestoreController.RestoreUpdateRecord actual =
+ actualUpdates.get(i);
+ assertEquals(expected.oldId, actual.oldId);
+ assertEquals(expected.newId, actual.newId);
+ assertEquals(expected.notified, actual.notified);
+ }
+ }
+
+ @NonNull
+ private static Set<String> getMockPrunedApps() {
+ final Set<String> mockPrunedApps = new ArraySet<>(10);
+ for (int i = 0; i < 10; i++) {
+ mockPrunedApps.add("com.example.app" + i);
+ }
+ return mockPrunedApps;
+ }
+
+ @NonNull
+ private static SparseArray<
+ List<AppWidgetServiceImpl.BackupRestoreController.RestoreUpdateRecord>
+ > getMockUpdates() {
+ final SparseArray<List<
+ AppWidgetServiceImpl.BackupRestoreController.RestoreUpdateRecord>> ret =
+ new SparseArray<>(4);
+ ret.put(0, new ArrayList<>());
+ for (int i = 0; i < 5; i++) {
+ final AppWidgetServiceImpl.BackupRestoreController.RestoreUpdateRecord record =
+ new AppWidgetServiceImpl.BackupRestoreController.RestoreUpdateRecord(
+ 5 - i, i);
+ record.notified = (i % 2 == 1);
+ final int key = (i < 3) ? 1 : 2;
+ if (!ret.contains(key)) {
+ ret.put(key, new ArrayList<>());
+ }
+ ret.get(key).add(record);
+ }
+ ret.put(3, new ArrayList<>());
+ return ret;
+ }
+
private int setupHostAndWidget() {
List<PendingHostUpdate> updates = mService.startListening(
mMockHost, mPkgName, HOST_ID, new int[0]).getList();
@@ -418,6 +509,40 @@
return mTestContext.getResources().getInteger(resId);
}
+ private static void saveBackupRestoreControllerState(
+ @NonNull final File dst,
+ @Nullable final AppWidgetServiceImpl.BackupRestoreController.State state)
+ throws IOException {
+ Objects.requireNonNull(dst);
+ if (state == null) {
+ return;
+ }
+ final AtomicFile file = new AtomicFile(dst);
+ final FileOutputStream stream = file.startWrite();
+ final TypedXmlSerializer out = Xml.resolveSerializer(stream);
+ out.startDocument(null, true);
+ AppWidgetXmlUtil.writeBackupRestoreControllerState(out, state);
+ out.endDocument();
+ file.finishWrite(stream);
+ }
+
+ private static AppWidgetServiceImpl.BackupRestoreController.State loadStateLocked(
+ @NonNull final File dst) {
+ Objects.requireNonNull(dst);
+ final AtomicFile file = new AtomicFile(dst);
+ try (FileInputStream stream = file.openRead()) {
+ final TypedXmlPullParser parser = Xml.resolvePullParser(stream);
+ int type;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && type != XmlPullParser.START_TAG) {
+ // drain whitespace, comments, etc.
+ }
+ return AppWidgetXmlUtil.readBackupRestoreControllerState(parser);
+ } catch (IOException | XmlPullParserException e) {
+ return null;
+ }
+ }
+
private static void saveWidgetProviderInfoLocked(@NonNull final File dst,
@Nullable final AppWidgetProviderInfo info)
throws IOException {
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
index 503ab8e..0f38532 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
@@ -79,6 +79,9 @@
import android.os.RemoteException;
import android.os.UserManager;
import android.platform.test.annotations.Presubmit;
+import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.platform.test.flag.junit.SetFlagsRule;
import android.security.GateKeeper;
import android.security.KeyStoreAuthorization;
@@ -118,6 +121,8 @@
@Rule
public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+ @Rule
+ public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
private static final String TEST_PACKAGE_NAME = "test_package";
private static final long TEST_REQUEST_ID = 44;
@@ -1506,6 +1511,75 @@
}
@Test
+ @RequiresFlagsEnabled(Flags.FLAG_MANDATORY_BIOMETRICS)
+ public void testCanAuthenticate_whenMandatoryBiometricsRequested()
+ throws Exception {
+ mBiometricService = new BiometricService(mContext, mInjector, mBiometricHandlerProvider);
+ mBiometricService.onStart();
+
+ when(mTrustManager.isInSignificantPlace()).thenReturn(false);
+ when(mBiometricService.mSettingObserver.getMandatoryBiometricsEnabledForUser(anyInt()))
+ .thenReturn(true);
+
+ setupAuthForOnly(TYPE_FINGERPRINT, Authenticators.BIOMETRIC_STRONG);
+
+ assertEquals(BiometricManager.BIOMETRIC_SUCCESS,
+ invokeCanAuthenticate(mBiometricService, Authenticators.MANDATORY_BIOMETRICS));
+
+ when(mTrustManager.isInSignificantPlace()).thenReturn(true);
+
+ assertEquals(BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE,
+ invokeCanAuthenticate(mBiometricService, Authenticators.MANDATORY_BIOMETRICS));
+ }
+
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_MANDATORY_BIOMETRICS)
+ public void testCanAuthenticate_whenMandatoryBiometricsAndStrongAuthenticatorsRequested()
+ throws Exception {
+ mBiometricService = new BiometricService(mContext, mInjector, mBiometricHandlerProvider);
+ mBiometricService.onStart();
+
+ when(mTrustManager.isInSignificantPlace()).thenReturn(false);
+ when(mBiometricService.mSettingObserver.getMandatoryBiometricsEnabledForUser(anyInt()))
+ .thenReturn(true);
+
+ setupAuthForOnly(TYPE_FINGERPRINT, Authenticators.BIOMETRIC_STRONG);
+
+ assertEquals(BiometricManager.BIOMETRIC_SUCCESS,
+ invokeCanAuthenticate(mBiometricService, Authenticators.MANDATORY_BIOMETRICS
+ | Authenticators.BIOMETRIC_STRONG));
+
+ when(mTrustManager.isInSignificantPlace()).thenReturn(true);
+
+ assertEquals(BiometricManager.BIOMETRIC_SUCCESS,
+ invokeCanAuthenticate(mBiometricService, Authenticators.MANDATORY_BIOMETRICS
+ | Authenticators.BIOMETRIC_STRONG));
+ }
+
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_MANDATORY_BIOMETRICS)
+ public void testCanAuthenticate_whenMandatoryBiometricsRequestedAndDeviceCredentialAvailable()
+ throws Exception {
+ mBiometricService = new BiometricService(mContext, mInjector, mBiometricHandlerProvider);
+ mBiometricService.onStart();
+
+ when(mTrustManager.isInSignificantPlace()).thenReturn(false);
+ when(mBiometricService.mSettingObserver.getMandatoryBiometricsEnabledForUser(anyInt()))
+ .thenReturn(true);
+
+ setupAuthForOnly(TYPE_CREDENTIAL, Authenticators.DEVICE_CREDENTIAL);
+
+ assertEquals(BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE,
+ invokeCanAuthenticate(mBiometricService, Authenticators.MANDATORY_BIOMETRICS));
+
+ when(mTrustManager.isInSignificantPlace()).thenReturn(true);
+
+ assertEquals(BiometricManager.BIOMETRIC_SUCCESS,
+ invokeCanAuthenticate(mBiometricService, Authenticators.MANDATORY_BIOMETRICS
+ | Authenticators.DEVICE_CREDENTIAL));
+ }
+
+ @Test
public void testAuthenticatorActualStrength() {
// Tuple of OEM config, updatedStrength, and expectedStrength
final int[][] testCases = {
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/PreAuthInfoTest.java b/services/tests/servicestests/src/com/android/server/biometrics/PreAuthInfoTest.java
index b40d7ee..b831ef5 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/PreAuthInfoTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/PreAuthInfoTest.java
@@ -32,11 +32,16 @@
import android.app.admin.DevicePolicyManager;
import android.app.trust.ITrustManager;
import android.content.Context;
+import android.content.res.Resources;
import android.hardware.biometrics.BiometricManager;
+import android.hardware.biometrics.Flags;
import android.hardware.biometrics.IBiometricAuthenticator;
import android.hardware.biometrics.PromptInfo;
import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
+import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import androidx.test.filters.SmallTest;
@@ -54,6 +59,9 @@
public class PreAuthInfoTest {
@Rule
public final MockitoRule mMockitoRule = MockitoJUnit.rule();
+ @Rule
+ public final CheckFlagsRule mCheckFlagsRule =
+ DeviceFlagsValueProvider.createCheckFlagsRule();
private static final int SENSOR_ID_FINGERPRINT = 0;
private static final int SENSOR_ID_FACE = 1;
@@ -66,6 +74,8 @@
@Mock
Context mContext;
@Mock
+ Resources mResources;
+ @Mock
ITrustManager mTrustManager;
@Mock
DevicePolicyManager mDevicePolicyManager;
@@ -80,6 +90,7 @@
when(mDevicePolicyManager.getKeyguardDisabledFeatures(any(), anyInt()))
.thenReturn(KEYGUARD_DISABLE_FEATURES_NONE);
when(mSettingObserver.getEnabledForApps(anyInt())).thenReturn(true);
+ when(mSettingObserver.getMandatoryBiometricsEnabledForUser(anyInt())).thenReturn(true);
when(mFaceAuthenticator.hasEnrolledTemplates(anyInt(), any())).thenReturn(true);
when(mFaceAuthenticator.isHardwareDetected(any())).thenReturn(true);
when(mFaceAuthenticator.getLockoutModeForUser(anyInt()))
@@ -91,6 +102,8 @@
.thenReturn(LOCKOUT_NONE);
when(mBiometricCameraManager.isCameraPrivacyEnabled()).thenReturn(false);
when(mBiometricCameraManager.isAnyCameraUnavailable()).thenReturn(false);
+ when(mContext.getResources()).thenReturn(mResources);
+ when(mResources.getString(anyInt())).thenReturn(TEST_PACKAGE_NAME);
}
@Test
@@ -184,6 +197,54 @@
assertThat(preAuthInfo.eligibleSensors.get(0).modality).isEqualTo(TYPE_FINGERPRINT);
}
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_MANDATORY_BIOMETRICS)
+ public void testMandatoryBiometricsStatus_whenAllRequirementsSatisfiedAndSensorAvailable()
+ throws Exception {
+ when(mTrustManager.isInSignificantPlace()).thenReturn(false);
+
+ final BiometricSensor sensor = getFaceSensor();
+ final PromptInfo promptInfo = new PromptInfo();
+ promptInfo.setAuthenticators(BiometricManager.Authenticators.MANDATORY_BIOMETRICS);
+ final PreAuthInfo preAuthInfo = PreAuthInfo.create(mTrustManager, mDevicePolicyManager,
+ mSettingObserver, List.of(sensor), 0 /* userId */, promptInfo, TEST_PACKAGE_NAME,
+ false /* checkDevicePolicyManager */, mContext, mBiometricCameraManager);
+
+ assertThat(preAuthInfo.eligibleSensors).hasSize(1);
+ }
+
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_MANDATORY_BIOMETRICS)
+ public void testMandatoryBiometricsStatus_whenAllRequirementsSatisfiedAndSensorUnavailable()
+ throws Exception {
+ when(mTrustManager.isInSignificantPlace()).thenReturn(false);
+
+ final PromptInfo promptInfo = new PromptInfo();
+ promptInfo.setAuthenticators(BiometricManager.Authenticators.MANDATORY_BIOMETRICS);
+ final PreAuthInfo preAuthInfo = PreAuthInfo.create(mTrustManager, mDevicePolicyManager,
+ mSettingObserver, List.of(), 0 /* userId */, promptInfo, TEST_PACKAGE_NAME,
+ false /* checkDevicePolicyManager */, mContext, mBiometricCameraManager);
+
+ assertThat(preAuthInfo.eligibleSensors).hasSize(0);
+ }
+
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_MANDATORY_BIOMETRICS)
+ public void testMandatoryBiometricsStatus_whenRequirementsNotSatisfiedAndSensorAvailable()
+ throws Exception {
+ when(mTrustManager.isInSignificantPlace()).thenReturn(true);
+
+ final BiometricSensor sensor = getFaceSensor();
+ final PromptInfo promptInfo = new PromptInfo();
+ promptInfo.setAuthenticators(BiometricManager.Authenticators.MANDATORY_BIOMETRICS
+ | BiometricManager.Authenticators.BIOMETRIC_STRONG);
+ final PreAuthInfo preAuthInfo = PreAuthInfo.create(mTrustManager, mDevicePolicyManager,
+ mSettingObserver, List.of(sensor), 0 /* userId */, promptInfo, TEST_PACKAGE_NAME,
+ false /* checkDevicePolicyManager */, mContext, mBiometricCameraManager);
+
+ assertThat(preAuthInfo.eligibleSensors).hasSize(1);
+ }
+
private BiometricSensor getFingerprintSensor() {
BiometricSensor sensor = new BiometricSensor(mContext, SENSOR_ID_FINGERPRINT,
TYPE_FINGERPRINT, BiometricManager.Authenticators.BIOMETRIC_STRONG,
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/UtilsTest.java b/services/tests/servicestests/src/com/android/server/biometrics/UtilsTest.java
index b05a819..cb75e1a 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/UtilsTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/UtilsTest.java
@@ -179,7 +179,8 @@
// The rest of the bits are not allowed to integrate with the public APIs
for (int i = 8; i < 32; i++) {
final int authenticator = 1 << i;
- if (authenticator == Authenticators.DEVICE_CREDENTIAL) {
+ if (authenticator == Authenticators.DEVICE_CREDENTIAL
+ || authenticator == Authenticators.MANDATORY_BIOMETRICS) {
continue;
}
assertFalse(Utils.isValidAuthenticatorConfig(1 << i));
diff --git a/services/tests/servicestests/src/com/android/server/compat/ApplicationInfoBuilder.java b/services/tests/servicestests/src/com/android/server/compat/ApplicationInfoBuilder.java
index c165c66..d8fd266a 100644
--- a/services/tests/servicestests/src/com/android/server/compat/ApplicationInfoBuilder.java
+++ b/services/tests/servicestests/src/com/android/server/compat/ApplicationInfoBuilder.java
@@ -21,8 +21,10 @@
class ApplicationInfoBuilder {
private boolean mIsDebuggable;
private int mTargetSdk;
+ private int mUid;
private String mPackageName;
private long mVersionCode;
+ private boolean mIsSystemApp;
private ApplicationInfoBuilder() {
mTargetSdk = -1;
@@ -42,6 +44,16 @@
return this;
}
+ ApplicationInfoBuilder systemApp() {
+ mIsSystemApp = true;
+ return this;
+ }
+
+ ApplicationInfoBuilder withUid(int uid) {
+ mUid = uid;
+ return this;
+ }
+
ApplicationInfoBuilder withPackageName(String packageName) {
mPackageName = packageName;
return this;
@@ -60,6 +72,10 @@
applicationInfo.packageName = mPackageName;
applicationInfo.targetSdkVersion = mTargetSdk;
applicationInfo.longVersionCode = mVersionCode;
+ applicationInfo.uid = mUid;
+ if (mIsSystemApp) {
+ applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
+ }
return applicationInfo;
}
}
diff --git a/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java b/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java
index 9accd49..9df7a36 100644
--- a/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java
+++ b/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java
@@ -29,6 +29,7 @@
import android.compat.Compatibility.ChangeConfig;
import android.content.Context;
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.os.Build;
@@ -36,6 +37,7 @@
import androidx.test.runner.AndroidJUnit4;
import com.android.internal.compat.AndroidBuildClassifier;
+import com.android.internal.compat.ChangeReporter;
import com.android.internal.compat.CompatibilityChangeConfig;
import com.android.internal.compat.CompatibilityChangeInfo;
import com.android.server.LocalServices;
@@ -65,6 +67,8 @@
CompatConfig mCompatConfig;
@Mock
private AndroidBuildClassifier mBuildClassifier;
+ @Mock
+ private ChangeReporter mChangeReporter;
@Before
public void setUp() throws Exception {
@@ -78,7 +82,8 @@
when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
.thenThrow(new PackageManager.NameNotFoundException());
mCompatConfig = new CompatConfig(mBuildClassifier, mContext);
- mPlatformCompat = new PlatformCompat(mContext, mCompatConfig, mBuildClassifier);
+ mPlatformCompat =
+ new PlatformCompat(mContext, mCompatConfig, mBuildClassifier, mChangeReporter);
// Assume userdebug/eng non-final build
mCompatConfig.forceNonDebuggableFinalForTest(false);
when(mBuildClassifier.isDebuggableBuild()).thenReturn(true);
@@ -100,7 +105,8 @@
.addLoggingOnlyChangeWithId(7L)
.addDisabledOverridableChangeWithId(8L)
.build();
- mPlatformCompat = new PlatformCompat(mContext, mCompatConfig, mBuildClassifier);
+ mPlatformCompat =
+ new PlatformCompat(mContext, mCompatConfig, mBuildClassifier, mChangeReporter);
assertThat(mPlatformCompat.listAllChanges()).asList().containsExactly(
new CompatibilityChangeInfo(1L, "", -1, -1, false, false, "", false),
new CompatibilityChangeInfo(2L, "change2", -1, -1, true, false, "", false),
@@ -128,7 +134,8 @@
.addLoggingOnlyChangeWithId(7L)
.addEnableSinceSdkChangeWithId(31, 8L)
.build();
- mPlatformCompat = new PlatformCompat(mContext, mCompatConfig, mBuildClassifier);
+ mPlatformCompat =
+ new PlatformCompat(mContext, mCompatConfig, mBuildClassifier, mChangeReporter);
assertThat(mPlatformCompat.listUIChanges()).asList().containsExactly(
new CompatibilityChangeInfo(1L, "", -1, -1, false, false, "", false),
new CompatibilityChangeInfo(2L, "change2", -1, -1, true, false, "", false),
@@ -146,7 +153,8 @@
.addEnableAfterSdkChangeWithId(Build.VERSION_CODES.O, 3L)
.build();
mCompatConfig.forceNonDebuggableFinalForTest(true);
- mPlatformCompat = new PlatformCompat(mContext, mCompatConfig, mBuildClassifier);
+ mPlatformCompat =
+ new PlatformCompat(mContext, mCompatConfig, mBuildClassifier, mChangeReporter);
// Before adding overrides.
assertThat(mPlatformCompat.isChangeEnabledByPackageName(1, PACKAGE_NAME, 0)).isTrue();
@@ -369,4 +377,68 @@
// Listener not called when a non existing override is removed.
verify(mListener1, never()).onCompatChange(PACKAGE_NAME);
}
+
+ @Test
+ public void testReportChange() throws Exception {
+ ApplicationInfo appInfo = ApplicationInfoBuilder.create().withUid(123).build();
+ mPlatformCompat.reportChange(1L, appInfo);
+ verify(mChangeReporter).reportChange(123, 1L, ChangeReporter.STATE_LOGGED, false, true);
+
+ ApplicationInfo systemAppInfo =
+ ApplicationInfoBuilder.create().withUid(123).systemApp().build();
+ mPlatformCompat.reportChange(1L, systemAppInfo);
+ verify(mChangeReporter).reportChange(123, 1L, ChangeReporter.STATE_LOGGED, true, true);
+ }
+
+ @Test
+ public void testReportChangeByPackageName() throws Exception {
+ when(mPackageManagerInternal.getApplicationInfo(
+ eq(PACKAGE_NAME), eq(0L), anyInt(), anyInt()))
+ .thenReturn(
+ ApplicationInfoBuilder.create()
+ .withPackageName(PACKAGE_NAME)
+ .withUid(123)
+ .build());
+
+ mPlatformCompat.reportChangeByPackageName(1L, PACKAGE_NAME, 123);
+ verify(mChangeReporter).reportChange(123, 1L, ChangeReporter.STATE_LOGGED, false, true);
+
+ String SYSTEM_PACKAGE_NAME = "my.system.package";
+
+ when(mPackageManagerInternal.getApplicationInfo(
+ eq(SYSTEM_PACKAGE_NAME), eq(0L), anyInt(), anyInt()))
+ .thenReturn(
+ ApplicationInfoBuilder.create()
+ .withPackageName(SYSTEM_PACKAGE_NAME)
+ .withUid(123)
+ .systemApp()
+ .build());
+
+ mPlatformCompat.reportChangeByPackageName(1L, SYSTEM_PACKAGE_NAME, 123);
+ verify(mChangeReporter).reportChange(123, 1L, ChangeReporter.STATE_LOGGED, true, true);
+ }
+
+ @Test
+ public void testIsChangeEnabled() throws Exception {
+ mCompatConfig =
+ CompatConfigBuilder.create(mBuildClassifier, mContext)
+ .addEnabledChangeWithId(1L)
+ .addDisabledChangeWithId(2L)
+ .addEnabledChangeWithId(3L)
+ .build();
+ mCompatConfig.forceNonDebuggableFinalForTest(true);
+ mPlatformCompat =
+ new PlatformCompat(mContext, mCompatConfig, mBuildClassifier, mChangeReporter);
+
+ ApplicationInfo appInfo = ApplicationInfoBuilder.create().withUid(123).build();
+ assertThat(mPlatformCompat.isChangeEnabled(1L, appInfo)).isTrue();
+ verify(mChangeReporter).reportChange(123, 1L, ChangeReporter.STATE_ENABLED, false, false);
+ assertThat(mPlatformCompat.isChangeEnabled(2L, appInfo)).isFalse();
+ verify(mChangeReporter).reportChange(123, 2L, ChangeReporter.STATE_DISABLED, false, false);
+
+ ApplicationInfo systemAppInfo =
+ ApplicationInfoBuilder.create().withUid(123).systemApp().build();
+ assertThat(mPlatformCompat.isChangeEnabled(3L, systemAppInfo)).isTrue();
+ verify(mChangeReporter).reportChange(123, 3L, ChangeReporter.STATE_ENABLED, true, false);
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java
index f9077c4..93fc071a 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java
@@ -196,11 +196,6 @@
}
@Override
- void setKeystorePassword(byte[] password, int userHandle) {
-
- }
-
- @Override
void initKeystoreSuperKeys(int userId, SyntheticPassword sp, boolean allowExisting) {
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 398dc281..c1d7afb 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -40,6 +40,7 @@
import static android.app.Notification.FLAG_ONLY_ALERT_ONCE;
import static android.app.Notification.FLAG_USER_INITIATED_JOB;
import static android.app.Notification.VISIBILITY_PRIVATE;
+import static android.app.NotificationChannel.NEWS_ID;
import static android.app.NotificationChannel.USER_LOCKED_ALLOW_BUBBLE;
import static android.app.NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED;
import static android.app.NotificationManager.BUBBLE_PREFERENCE_ALL;
@@ -91,7 +92,9 @@
import static android.service.notification.Adjustment.KEY_CONTEXTUAL_ACTIONS;
import static android.service.notification.Adjustment.KEY_IMPORTANCE;
import static android.service.notification.Adjustment.KEY_TEXT_REPLIES;
+import static android.service.notification.Adjustment.KEY_TYPE;
import static android.service.notification.Adjustment.KEY_USER_SENTIMENT;
+import static android.service.notification.Adjustment.TYPE_NEWS;
import static android.service.notification.Condition.SOURCE_CONTEXT;
import static android.service.notification.Condition.SOURCE_USER_ACTION;
import static android.service.notification.Condition.STATE_TRUE;
@@ -15778,4 +15781,27 @@
when(mPackageManagerInternal.isSameApp(anyString(), anyInt(), anyInt())).thenReturn(false);
assertThat(mBinderService.getEffectsSuppressor()).isEqualTo(mListener.component);
}
+
+ @Test
+ @EnableFlags(android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION)
+ public void testApplyAdjustment_keyType_validType() throws Exception {
+ final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
+ mService.addNotification(r);
+ NotificationManagerService.WorkerHandler handler = mock(
+ NotificationManagerService.WorkerHandler.class);
+ mService.setHandler(handler);
+
+ Bundle signals = new Bundle();
+ signals.putInt(KEY_TYPE, TYPE_NEWS);
+ Adjustment adjustment = new Adjustment(
+ r.getSbn().getPackageName(), r.getKey(), signals, "", r.getUser().getIdentifier());
+ when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
+ mBinderService.applyAdjustmentFromAssistant(null, adjustment);
+
+ waitForIdle();
+
+ r.applyAdjustments();
+
+ assertThat(r.getChannel().getId()).isEqualTo(NEWS_ID);
+ }
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationVisitUrisTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationVisitUrisTest.java
index 594d6f2..6a99731 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationVisitUrisTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationVisitUrisTest.java
@@ -37,6 +37,7 @@
import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
import android.util.Log;
+import android.util.proto.ProtoOutputStream;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.RemoteViews;
@@ -105,7 +106,7 @@
private static final ImmutableSet<Class<?>> UNUSABLE_TYPES =
ImmutableSet.of(Consumer.class, IBinder.class, MediaSession.Token.class, Parcel.class,
PrintWriter.class, Resources.Theme.class, View.class,
- LayoutInflater.Factory2.class);
+ LayoutInflater.Factory2.class, ProtoOutputStream.class);
// Maximum number of times we allow generating the same class recursively.
// E.g. new RemoteViews.addView(new RemoteViews()) but stop there.
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
index d1880d2..ff4bc21 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -23,6 +23,10 @@
import static android.app.NotificationChannel.ALLOW_BUBBLE_ON;
import static android.app.NotificationChannel.CONVERSATION_CHANNEL_ID_FORMAT;
import static android.app.NotificationChannel.DEFAULT_ALLOW_BUBBLE;
+import static android.app.NotificationChannel.NEWS_ID;
+import static android.app.NotificationChannel.PROMOTIONS_ID;
+import static android.app.NotificationChannel.RECS_ID;
+import static android.app.NotificationChannel.SOCIAL_MEDIA_ID;
import static android.app.NotificationChannel.USER_LOCKED_ALLOW_BUBBLE;
import static android.app.NotificationChannel.USER_LOCKED_IMPORTANCE;
import static android.app.NotificationChannel.USER_LOCKED_LIGHTS;
@@ -47,6 +51,9 @@
import static android.os.UserHandle.USER_SYSTEM;
import static android.platform.test.flag.junit.SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT;
+import static android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION;
+import static android.service.notification.Flags.notificationClassification;
+
import static com.android.internal.config.sysui.SystemUiSystemPropertiesFlags.NotificationFlags.PROPAGATE_CHANNEL_UPDATES_TO_CONVERSATIONS;
import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_PREFERENCES__FSI_STATE__DENIED;
import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_PREFERENCES__FSI_STATE__GRANTED;
@@ -184,6 +191,7 @@
@SmallTest
@RunWith(ParameterizedAndroidJunit4.class)
+@EnableFlags(FLAG_PERSIST_INCOMPLETE_RESTORE_DATA)
public class PreferencesHelperTest extends UiServiceTestCase {
private static final int UID_HEADLESS = 1000000;
private static final UserHandle USER = UserHandle.of(0);
@@ -233,7 +241,7 @@
@Parameters(name = "{0}")
public static List<FlagsParameterization> getParams() {
return FlagsParameterization.allCombinationsOf(
- FLAG_PERSIST_INCOMPLETE_RESTORE_DATA);
+ FLAG_NOTIFICATION_CLASSIFICATION);
}
public PreferencesHelperTest(FlagsParameterization flags) {
@@ -582,6 +590,16 @@
assertTrue(mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2, false, false,
UID_N_MR1, false));
+ NotificationChannel updateNews = null;
+ if (notificationClassification()) {
+ // change one of the reserved bundle channels to ensure changes are persisted across
+ // boot
+ updateNews = mHelper.getNotificationChannel(
+ PKG_N_MR1, UID_N_MR1, NEWS_ID, false).copy();
+ updateNews.setImportance(IMPORTANCE_NONE);
+ mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, updateNews, true, 1000, true);
+ }
+
mHelper.setShowBadge(PKG_N_MR1, UID_N_MR1, true);
ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, false,
@@ -597,6 +615,12 @@
mXmlHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1.getId(), false));
compareChannels(channel2,
mXmlHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2.getId(), false));
+ if (notificationClassification()) {
+ assertThat(mXmlHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, updateNews.getId(),
+ false)).isNotNull();
+ assertThat(mXmlHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, updateNews.getId(),
+ false)).isEqualTo(updateNews);
+ }
List<NotificationChannelGroup> actualGroups = mXmlHelper.getNotificationChannelGroups(
PKG_N_MR1, UID_N_MR1, false, true, false, true, null).getList();
@@ -1130,9 +1154,22 @@
+ "app_user_locked_fields=\"0\" sent_invalid_msg=\"false\" "
+ "sent_valid_msg=\"false\" user_demote_msg_app=\"false\" sent_valid_bubble"
+ "=\"false\" uid=\"10002\">\n"
+ + (notificationClassification() ? "<channel id=\"android.app.social\" "
+ + "name=\"Social\" importance=\"2\" "
+ + "sound=\"content://settings/system/notification_sound\" "
+ + "usage=\"5\" content_type=\"4\" flags=\"0\" show_badge=\"true\" />\n" : "")
+ "<channel id=\"id\" name=\"name\" importance=\"2\" "
+ "sound=\"content://settings/system/notification_sound\" usage=\"5\" "
+ "content_type=\"4\" flags=\"0\" show_badge=\"true\" orig_imp=\"2\" />\n"
+ + (notificationClassification() ? "<channel id=\"android.app.news\" name=\"News\" "
+ + "importance=\"2\" sound=\"content://settings/system/notification_sound\" "
+ + "usage=\"5\" content_type=\"4\" flags=\"0\" show_badge=\"true\" />\n"
+ + "<channel id=\"android.app.recs\" name=\"Recommendations\" importance=\"2\" "
+ + "sound=\"content://settings/system/notification_sound\" usage=\"5\" "
+ + "content_type=\"4\" flags=\"0\" show_badge=\"true\" />\n"
+ + "<channel id=\"android.app.promotions\" name=\"Promotions\" importance=\"2\" "
+ + "sound=\"content://settings/system/notification_sound\" usage=\"5\" "
+ + "content_type=\"4\" flags=\"0\" show_badge=\"true\" />\n" : "")
+ "</package>\n"
+ "<package name=\"com.example.n_mr1\" show_badge=\"true\" "
+ "app_user_locked_fields=\"0\" sent_invalid_msg=\"false\" "
@@ -1140,6 +1177,10 @@
+ "=\"false\" uid=\"10001\">\n"
+ "<channelGroup id=\"1\" name=\"bye\" blocked=\"false\" locked=\"0\" />\n"
+ "<channelGroup id=\"2\" name=\"hello\" blocked=\"false\" locked=\"0\" />\n"
+ + (notificationClassification() ? "<channel id=\"android.app.social\" "
+ + "name=\"Social\" importance=\"2\" "
+ + "sound=\"content://settings/system/notification_sound\" "
+ + "usage=\"5\" content_type=\"4\" flags=\"0\" show_badge=\"true\" />\n" : "")
+ "<channel id=\"id1\" name=\"name1\" importance=\"4\" show_badge=\"true\" "
+ "orig_imp=\"4\" />\n"
+ "<channel id=\"id2\" name=\"name2\" desc=\"descriptions for all\" "
@@ -1149,14 +1190,22 @@
+ "sound=\"content://settings/system/notification_sound\" usage=\"5\" "
+ "content_type=\"4\" flags=\"0\" vibration_enabled=\"true\" show_badge=\"true\" "
+ "orig_imp=\"4\" />\n"
+ + (notificationClassification() ? "<channel id=\"android.app.news\" name=\"News\" "
+ + "importance=\"2\" sound=\"content://settings/system/notification_sound\" "
+ + "usage=\"5\" content_type=\"4\" flags=\"0\" show_badge=\"true\" />\n"
+ + "<channel id=\"android.app.recs\" name=\"Recommendations\" importance=\"2\" "
+ + "sound=\"content://settings/system/notification_sound\" usage=\"5\" "
+ + "content_type=\"4\" flags=\"0\" show_badge=\"true\" />\n"
+ + "<channel id=\"android.app.promotions\" name=\"Promotions\" importance=\"2\" "
+ + "sound=\"content://settings/system/notification_sound\" usage=\"5\" "
+ + "content_type=\"4\" flags=\"0\" show_badge=\"true\" />\n" : "")
+ "<channel id=\"miscellaneous\" name=\"Uncategorized\" "
+ "sound=\"content://settings/system/notification_sound\" usage=\"5\" "
+ "content_type=\"4\" flags=\"0\" show_badge=\"true\" />\n"
+ "</package>\n"
+ "<package name=\"com.example.p\" show_badge=\"true\" "
+ "app_user_locked_fields=\"0\" sent_invalid_msg=\"true\" sent_valid_msg=\"true\""
- + " user_demote_msg_app=\"true\" sent_valid_bubble=\"false\" uid=\"10003\" />\n"
- + "</ranking>";
+ + " user_demote_msg_app=\"true\" sent_valid_bubble=\"false\" uid=\"10003\"";
assertThat(baos.toString()).contains(expected);
}
@@ -1216,9 +1265,22 @@
+ "app_user_locked_fields=\"0\" sent_invalid_msg=\"false\" "
+ "sent_valid_msg=\"false\" user_demote_msg_app=\"false\" sent_valid_bubble"
+ "=\"false\">\n"
+ + (notificationClassification() ? "<channel id=\"android.app.social\" "
+ + "name=\"Social\" importance=\"2\" "
+ + "sound=\"content://settings/system/notification_sound\" "
+ + "usage=\"5\" content_type=\"4\" flags=\"0\" show_badge=\"true\" />\n" : "")
+ "<channel id=\"id\" name=\"name\" importance=\"2\" "
+ "sound=\"content://settings/system/notification_sound\" usage=\"5\" "
+ "content_type=\"4\" flags=\"0\" show_badge=\"true\" orig_imp=\"2\" />\n"
+ + (notificationClassification() ? "<channel id=\"android.app.news\" name=\"News\" "
+ + "importance=\"2\" sound=\"content://settings/system/notification_sound\" "
+ + "usage=\"5\" content_type=\"4\" flags=\"0\" show_badge=\"true\" />\n"
+ + "<channel id=\"android.app.recs\" name=\"Recommendations\" importance=\"2\" "
+ + "sound=\"content://settings/system/notification_sound\" usage=\"5\" "
+ + "content_type=\"4\" flags=\"0\" show_badge=\"true\" />\n"
+ + "<channel id=\"android.app.promotions\" name=\"Promotions\" importance=\"2\" "
+ + "sound=\"content://settings/system/notification_sound\" usage=\"5\" "
+ + "content_type=\"4\" flags=\"0\" show_badge=\"true\" />\n" : "")
+ "</package>\n"
// Importance default because on in permission helper
+ "<package name=\"com.example.n_mr1\" importance=\"3\" show_badge=\"true\" "
@@ -1227,6 +1289,10 @@
+ "=\"false\">\n"
+ "<channelGroup id=\"1\" name=\"bye\" blocked=\"false\" locked=\"0\" />\n"
+ "<channelGroup id=\"2\" name=\"hello\" blocked=\"false\" locked=\"0\" />\n"
+ + (notificationClassification() ? "<channel id=\"android.app.social\" "
+ + "name=\"Social\" importance=\"2\" "
+ + "sound=\"content://settings/system/notification_sound\" "
+ + "usage=\"5\" content_type=\"4\" flags=\"0\" show_badge=\"true\" />\n" : "")
+ "<channel id=\"id1\" name=\"name1\" importance=\"4\" show_badge=\"true\" "
+ "orig_imp=\"4\" />\n"
+ "<channel id=\"id2\" name=\"name2\" desc=\"descriptions for all\" "
@@ -1236,6 +1302,15 @@
+ "sound=\"content://settings/system/notification_sound\" usage=\"5\" "
+ "content_type=\"4\" flags=\"0\" vibration_enabled=\"true\" show_badge=\"true\" "
+ "orig_imp=\"4\" />\n"
+ + (notificationClassification() ? "<channel id=\"android.app.news\" name=\"News\" "
+ + "importance=\"2\" sound=\"content://settings/system/notification_sound\" "
+ + "usage=\"5\" content_type=\"4\" flags=\"0\" show_badge=\"true\" />\n"
+ + "<channel id=\"android.app.recs\" name=\"Recommendations\" importance=\"2\" "
+ + "sound=\"content://settings/system/notification_sound\" usage=\"5\" "
+ + "content_type=\"4\" flags=\"0\" show_badge=\"true\" />\n"
+ + "<channel id=\"android.app.promotions\" name=\"Promotions\" importance=\"2\" "
+ + "sound=\"content://settings/system/notification_sound\" usage=\"5\" "
+ + "content_type=\"4\" flags=\"0\" show_badge=\"true\" />\n" : "")
+ "<channel id=\"miscellaneous\" name=\"Uncategorized\" "
+ "sound=\"content://settings/system/notification_sound\" usage=\"5\" "
+ "content_type=\"4\" flags=\"0\" show_badge=\"true\" />\n"
@@ -1243,12 +1318,11 @@
// Importance default because on in permission helper
+ "<package name=\"com.example.p\" importance=\"3\" show_badge=\"true\" "
+ "app_user_locked_fields=\"0\" sent_invalid_msg=\"true\" sent_valid_msg=\"true\""
- + " user_demote_msg_app=\"true\" sent_valid_bubble=\"false\" />\n"
- // Packages that exist solely in permissionhelper
- + "<package name=\"first\" importance=\"3\" />\n"
- + "<package name=\"third\" importance=\"0\" />\n"
- + "</ranking>";
+ + " user_demote_msg_app=\"true\" sent_valid_bubble=\"false\"";
assertThat(baos.toString()).contains(expected);
+ // Packages that exist solely in permissionhelper
+ assertThat(baos.toString()).contains("<package name=\"first\" importance=\"3\"");
+ assertThat(baos.toString()).contains("<package name=\"third\" importance=\"0\"");
}
@Test
@@ -1303,9 +1377,22 @@
+ "app_user_locked_fields=\"0\" sent_invalid_msg=\"false\" "
+ "sent_valid_msg=\"false\" user_demote_msg_app=\"false\" sent_valid_bubble"
+ "=\"false\">\n"
+ + (notificationClassification() ? "<channel id=\"android.app.social\" "
+ + "name=\"Social\" importance=\"2\" "
+ + "sound=\"content://settings/system/notification_sound\" usage=\"5\" "
+ + "content_type=\"4\" flags=\"0\" show_badge=\"true\" />\n" : "")
+ "<channel id=\"id\" name=\"name\" importance=\"2\" "
+ "sound=\"content://settings/system/notification_sound\" usage=\"5\" "
+ "content_type=\"4\" flags=\"0\" show_badge=\"true\" orig_imp=\"2\" />\n"
+ + (notificationClassification() ? "<channel id=\"android.app.news\" name=\"News\" "
+ + "importance=\"2\" sound=\"content://settings/system/notification_sound\" "
+ + "usage=\"5\" content_type=\"4\" flags=\"0\" show_badge=\"true\" />\n"
+ + "<channel id=\"android.app.recs\" name=\"Recommendations\" importance=\"2\" "
+ + "sound=\"content://settings/system/notification_sound\" usage=\"5\" "
+ + "content_type=\"4\" flags=\"0\" show_badge=\"true\" />\n"
+ + "<channel id=\"android.app.promotions\" name=\"Promotions\" importance=\"2\" "
+ + "sound=\"content://settings/system/notification_sound\" usage=\"5\" "
+ + "content_type=\"4\" flags=\"0\" show_badge=\"true\" />\n" : "")
+ "</package>\n"
// Importance 0 because missing from permission helper
+ "<package name=\"com.example.n_mr1\" importance=\"0\" show_badge=\"true\" "
@@ -1314,6 +1401,10 @@
+ "=\"false\">\n"
+ "<channelGroup id=\"1\" name=\"bye\" blocked=\"false\" locked=\"0\" />\n"
+ "<channelGroup id=\"2\" name=\"hello\" blocked=\"false\" locked=\"0\" />\n"
+ + (notificationClassification() ? "<channel id=\"android.app.social\" "
+ + "name=\"Social\" importance=\"2\" "
+ + "sound=\"content://settings/system/notification_sound\" usage=\"5\" "
+ + "content_type=\"4\" flags=\"0\" show_badge=\"true\" />\n" : "")
+ "<channel id=\"id1\" name=\"name1\" importance=\"4\" show_badge=\"true\" "
+ "orig_imp=\"4\" />\n"
+ "<channel id=\"id2\" name=\"name2\" desc=\"descriptions for all\" "
@@ -1323,6 +1414,15 @@
+ "sound=\"content://settings/system/notification_sound\" usage=\"5\" "
+ "content_type=\"4\" flags=\"0\" vibration_enabled=\"true\" show_badge=\"true\" "
+ "orig_imp=\"4\" />\n"
+ + (notificationClassification() ? "<channel id=\"android.app.news\" name=\"News\" "
+ + "importance=\"2\" sound=\"content://settings/system/notification_sound\" "
+ + "usage=\"5\" content_type=\"4\" flags=\"0\" show_badge=\"true\" />\n"
+ + "<channel id=\"android.app.recs\" name=\"Recommendations\" importance=\"2\" "
+ + "sound=\"content://settings/system/notification_sound\" usage=\"5\" "
+ + "content_type=\"4\" flags=\"0\" show_badge=\"true\" />\n"
+ + "<channel id=\"android.app.promotions\" name=\"Promotions\" importance=\"2\" "
+ + "sound=\"content://settings/system/notification_sound\" usage=\"5\" "
+ + "content_type=\"4\" flags=\"0\" show_badge=\"true\" />\n" : "")
+ "<channel id=\"miscellaneous\" name=\"Uncategorized\" "
+ "sound=\"content://settings/system/notification_sound\" usage=\"5\" "
+ "content_type=\"4\" flags=\"0\" show_badge=\"true\" />\n"
@@ -1330,8 +1430,7 @@
// Importance default because on in permission helper
+ "<package name=\"com.example.p\" importance=\"3\" show_badge=\"true\" "
+ "app_user_locked_fields=\"0\" sent_invalid_msg=\"true\" sent_valid_msg=\"true\""
- + " user_demote_msg_app=\"true\" sent_valid_bubble=\"false\" />\n"
- + "</ranking>";
+ + " user_demote_msg_app=\"true\" sent_valid_bubble=\"false\"";
assertThat(baos.toString()).contains(expected);
}
@@ -1851,8 +1950,8 @@
parser.nextTag();
mHelper.readXml(parser, false, UserHandle.USER_ALL);
- final NotificationChannel updated1 =
- mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, NotificationChannel.DEFAULT_CHANNEL_ID, false);
+ final NotificationChannel updated1 = mHelper.getNotificationChannel(
+ PKG_N_MR1, UID_N_MR1, NotificationChannel.DEFAULT_CHANNEL_ID, false);
assertEquals(NotificationManager.IMPORTANCE_HIGH, updated1.getImportance());
assertTrue(updated1.canBypassDnd());
assertEquals(VISIBILITY_SECRET, updated1.getLockscreenVisibility());
@@ -2392,18 +2491,20 @@
// Returns only non-deleted channels
List<NotificationChannel> channels =
mHelper.getNotificationChannels(PKG_N_MR1, UID_N_MR1, false).getList();
- assertEquals(2, channels.size()); // Default channel + non-deleted channel
+ // Default channel + non-deleted channel + system defaults
+ assertEquals(notificationClassification() ? 6 : 2, channels.size());
for (NotificationChannel nc : channels) {
- if (!NotificationChannel.DEFAULT_CHANNEL_ID.equals(nc.getId())) {
+ if (channel2.getId().equals(nc.getId())) {
compareChannels(channel2, nc);
}
}
// Returns deleted channels too
channels = mHelper.getNotificationChannels(PKG_N_MR1, UID_N_MR1, true).getList();
- assertEquals(3, channels.size()); // Includes default channel
+ // Includes system channel(s)
+ assertEquals(notificationClassification() ? 7 : 3, channels.size());
for (NotificationChannel nc : channels) {
- if (!NotificationChannel.DEFAULT_CHANNEL_ID.equals(nc.getId())) {
+ if (channel2.getId().equals(nc.getId())) {
compareChannels(channelMap.get(nc.getId()), nc);
}
}
@@ -3013,7 +3114,8 @@
final ApplicationInfo legacy = new ApplicationInfo();
legacy.targetSdkVersion = Build.VERSION_CODES.N_MR1;
- when(mPm.getApplicationInfoAsUser(eq(PKG_N_MR1), anyInt(), anyInt())).thenReturn(legacy);
+ when(mPm.getApplicationInfoAsUser(eq(PKG_N_MR1), anyInt(), anyInt()))
+ .thenReturn(legacy);
// create records with the default channel for all user 0 and user 1 uids
mHelper.canShowBadge(PKG_N_MR1, user0Uids[i]);
@@ -3024,13 +3126,14 @@
// user 0 records remain
for (int i = 0; i < user0Uids.length; i++) {
- assertEquals(1,
- mHelper.getNotificationChannels(PKG_N_MR1, user0Uids[i], false).getList().size());
+ assertEquals(notificationClassification() ? 5 : 1,
+ mHelper.getNotificationChannels(PKG_N_MR1, user0Uids[i], false)
+ .getList().size());
}
// user 1 records are gone
for (int i = 0; i < user1Uids.length; i++) {
- assertEquals(0,
- mHelper.getNotificationChannels(PKG_N_MR1, user1Uids[i], false).getList().size());
+ assertEquals(0, mHelper.getNotificationChannels(PKG_N_MR1, user1Uids[i], false)
+ .getList().size());
}
}
@@ -3054,7 +3157,8 @@
assertFalse(mHelper.onPackagesChanged(false, USER_SYSTEM,
new String[]{PKG_N_MR1}, new int[]{UID_N_MR1}));
- assertEquals(2, mHelper.getNotificationChannels(PKG_N_MR1, UID_N_MR1, false).getList().size());
+ assertEquals(notificationClassification() ? 6 : 2,
+ mHelper.getNotificationChannels(PKG_N_MR1, UID_N_MR1, false).getList().size());
}
@Test
@@ -3126,7 +3230,8 @@
@Test
public void testRecordDefaults() throws Exception {
assertEquals(true, mHelper.canShowBadge(PKG_N_MR1, UID_N_MR1));
- assertEquals(1, mHelper.getNotificationChannels(PKG_N_MR1, UID_N_MR1, false).getList().size());
+ assertEquals(notificationClassification() ? 5 : 1,
+ mHelper.getNotificationChannels(PKG_N_MR1, UID_N_MR1, false).getList().size());
}
@Test
@@ -3212,7 +3317,9 @@
assertEquals(3, actual.size());
for (NotificationChannelGroup group : actual) {
if (group.getId() == null) {
- assertEquals(2, group.getChannels().size()); // misc channel too
+ assertEquals(
+ notificationClassification() ? 6 : 2,
+ group.getChannels().size()); // misc channel too
assertTrue(channel3.getId().equals(group.getChannels().get(0).getId())
|| channel3.getId().equals(group.getChannels().get(1).getId()));
} else if (group.getId().equals(ncg.getId())) {
@@ -3363,6 +3470,9 @@
new NotificationChannel("" + j, "a", IMPORTANCE_HIGH), true, false,
UID_N_MR1, false);
}
+ if (notificationClassification()) {
+ numChannels += 4;
+ }
expectedChannels.put(pkgName, numChannels);
}
@@ -4583,7 +4693,12 @@
@Test
public void testTooManyChannels() {
- for (int i = 0; i < NOTIFICATION_CHANNEL_COUNT_LIMIT; i++) {
+ int numToCreate = NOTIFICATION_CHANNEL_COUNT_LIMIT;
+ if (notificationClassification()) {
+ // reserved channels lower limit
+ numToCreate -= 4;
+ }
+ for (int i = 0; i < numToCreate; i++) {
NotificationChannel channel = new NotificationChannel(String.valueOf(i),
String.valueOf(i), NotificationManager.IMPORTANCE_HIGH);
mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, true, UID_O, false);
@@ -4602,11 +4717,16 @@
@Test
public void testTooManyChannels_xml() throws Exception {
+ int numToCreate = NOTIFICATION_CHANNEL_COUNT_LIMIT;
+ if (notificationClassification()) {
+ // reserved channels lower limit
+ numToCreate -= 4;
+ }
String extraChannel = "EXTRA";
String extraChannel1 = "EXTRA1";
// create first... many... directly so we don't need a big xml blob in this test
- for (int i = 0; i < NOTIFICATION_CHANNEL_COUNT_LIMIT; i++) {
+ for (int i = 0; i < numToCreate; i++) {
NotificationChannel channel = new NotificationChannel(String.valueOf(i),
String.valueOf(i), NotificationManager.IMPORTANCE_HIGH);
mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, true, UID_O, false);
@@ -5619,8 +5739,9 @@
ArrayList<StatsEvent> events = new ArrayList<>();
mHelper.pullPackageChannelPreferencesStats(events);
- // number of channels with preferences should be 3 total
- assertEquals("expected number of events", 3, events.size());
+ assertEquals("expected number of events",
+ notificationClassification() ? 7 : 3,
+ events.size());
for (StatsEvent ev : events) {
// all of these events should be of PackageNotificationChannelPreferences type,
// and therefore we expect the atom to have this field.
@@ -5643,7 +5764,7 @@
} else if (eventChannelId.equals("a")) {
assertEquals("channel name", "a", p.getChannelName());
assertEquals("importance", IMPORTANCE_LOW, p.getImportance());
- } else { // b
+ } else if (eventChannelId.equals("b")){ // b
assertEquals("channel name", "b", p.getChannelName());
assertEquals("importance", IMPORTANCE_HIGH, p.getImportance());
}
@@ -5661,11 +5782,17 @@
mHelper.createNotificationChannel(PKG_O, UID_O, channelC, true, false, UID_O, false);
List<String> channels = new LinkedList<>(Arrays.asList("a", "b", "c"));
+ if (notificationClassification()) {
+ channels.add(NEWS_ID);
+ channels.add(PROMOTIONS_ID);
+ channels.add(SOCIAL_MEDIA_ID);
+ channels.add(RECS_ID);
+ }
ArrayList<StatsEvent> events = new ArrayList<>();
mHelper.pullPackageChannelPreferencesStats(events);
- assertEquals("total events", 3, events.size());
+ assertEquals("total events", notificationClassification() ? 7 : 3, events.size());
for (StatsEvent ev : events) {
AtomsProto.Atom atom = StatsEventTestUtils.convertToAtom(ev);
assertTrue(atom.hasPackageNotificationChannelPreferences());
@@ -5699,7 +5826,7 @@
mHelper.pullPackageChannelPreferencesStats(events);
// In this case, we want to check the properties of the conversation channel (not parent)
- assertEquals("total events", 2, events.size());
+ assertEquals("total events", notificationClassification() ? 6 : 2, events.size());
for (StatsEvent ev : events) {
AtomsProto.Atom atom = StatsEventTestUtils.convertToAtom(ev);
assertTrue(atom.hasPackageNotificationChannelPreferences());
@@ -5731,7 +5858,9 @@
ArrayList<StatsEvent> events = new ArrayList<>();
mHelper.pullPackageChannelPreferencesStats(events);
- assertEquals("total events", 2, events.size());
+ assertEquals("total events",
+ notificationClassification() ? 6 : 2,
+ events.size());
for (StatsEvent ev : events) {
AtomsProto.Atom atom = StatsEventTestUtils.convertToAtom(ev);
assertTrue(atom.hasPackageNotificationChannelPreferences());
@@ -5762,7 +5891,9 @@
ArrayList<StatsEvent> events = new ArrayList<>();
mHelper.pullPackageChannelPreferencesStats(events);
- assertEquals("total events", 2, events.size());
+ assertEquals("total events",
+ notificationClassification() ? 6 : 2,
+ events.size());
for (StatsEvent ev : events) {
AtomsProto.Atom atom = StatsEventTestUtils.convertToAtom(ev);
assertTrue(atom.hasPackageNotificationChannelPreferences());
@@ -6044,6 +6175,23 @@
assertEquals(0, actual.getChannels().stream().filter(c -> c.getId().equals("id2")).count());
}
+ @Test
+ @EnableFlags(FLAG_NOTIFICATION_CLASSIFICATION)
+ public void testNotificationBundles() {
+ // do something that triggers settings creation for an app
+ mHelper.setShowBadge(PKG_O, UID_O, true);
+
+ // verify 4 reserved channels are created
+ assertThat(mHelper.getNotificationChannel(PKG_O, UID_O, NEWS_ID, false).getImportance())
+ .isEqualTo(IMPORTANCE_LOW);
+ assertThat(mHelper.getNotificationChannel(PKG_O, UID_O, PROMOTIONS_ID, false)
+ .getImportance()).isEqualTo(IMPORTANCE_LOW);
+ assertThat(mHelper.getNotificationChannel(PKG_O, UID_O, SOCIAL_MEDIA_ID, false)
+ .getImportance()).isEqualTo(IMPORTANCE_LOW);
+ assertThat(mHelper.getNotificationChannel(PKG_O, UID_O, RECS_ID, false).getImportance())
+ .isEqualTo(IMPORTANCE_LOW);
+ }
+
private static NotificationChannel cloneChannel(NotificationChannel original) {
Parcel parcel = Parcel.obtain();
try {
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
index 201b286..40b0d78 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
@@ -43,7 +43,6 @@
import static android.app.NotificationManager.Policy.PRIORITY_SENDERS_ANY;
import static android.app.NotificationManager.Policy.PRIORITY_SENDERS_CONTACTS;
import static android.app.NotificationManager.Policy.PRIORITY_SENDERS_STARRED;
-import static android.app.NotificationManager.Policy.STATE_CHANNELS_BYPASSING_DND;
import static android.app.NotificationManager.Policy.STATE_PRIORITY_CHANNELS_BLOCKED;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_BADGE;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
@@ -5013,6 +5012,48 @@
}
@Test
+ @EnableFlags({FLAG_MODES_API, FLAG_MODES_UI})
+ public void updateAutomaticZenRule_changeOwnerForSystemRule_allowed() {
+ when(mContext.checkCallingPermission(anyString()))
+ .thenReturn(PackageManager.PERMISSION_GRANTED);
+ AutomaticZenRule original = new AutomaticZenRule.Builder("Rule", Uri.EMPTY)
+ .setOwner(new ComponentName("android", "some.old.cps"))
+ .build();
+ String ruleId = mZenModeHelper.addAutomaticZenRule("android", original,
+ UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI, "reason", Process.SYSTEM_UID);
+
+ AutomaticZenRule update = new AutomaticZenRule.Builder("Rule", Uri.EMPTY)
+ .setOwner(new ComponentName("android", "brand.new.cps"))
+ .build();
+ mZenModeHelper.updateAutomaticZenRule(ruleId, update, UPDATE_ORIGIN_USER, "reason",
+ Process.SYSTEM_UID);
+
+ AutomaticZenRule result = mZenModeHelper.getAutomaticZenRule(ruleId);
+ assertThat(result).isNotNull();
+ assertThat(result.getOwner().getClassName()).isEqualTo("brand.new.cps");
+ }
+
+ @Test
+ @EnableFlags({FLAG_MODES_API, FLAG_MODES_UI})
+ public void updateAutomaticZenRule_changeOwnerForAppOwnedRule_ignored() {
+ AutomaticZenRule original = new AutomaticZenRule.Builder("Rule", Uri.EMPTY)
+ .setOwner(new ComponentName(mContext.getPackageName(), "old.third.party.cps"))
+ .build();
+ String ruleId = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(), original,
+ UPDATE_ORIGIN_APP, "reason", CUSTOM_PKG_UID);
+
+ AutomaticZenRule update = new AutomaticZenRule.Builder("Rule", Uri.EMPTY)
+ .setOwner(new ComponentName(mContext.getPackageName(), "new.third.party.cps"))
+ .build();
+ mZenModeHelper.updateAutomaticZenRule(ruleId, update, UPDATE_ORIGIN_USER, "reason",
+ Process.SYSTEM_UID);
+
+ AutomaticZenRule result = mZenModeHelper.getAutomaticZenRule(ruleId);
+ assertThat(result).isNotNull();
+ assertThat(result.getOwner().getClassName()).isEqualTo("old.third.party.cps");
+ }
+
+ @Test
@EnableFlags(FLAG_MODES_API)
public void removeAutomaticZenRule_propagatesOriginToEffectsApplier() {
mZenModeHelper.setDeviceEffectsApplier(mDeviceEffectsApplier);
diff --git a/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java b/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java
index d6c0fef..1875284 100644
--- a/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java
+++ b/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java
@@ -781,6 +781,34 @@
}
@Test
+ @RequiresFlagsEnabled(android.os.vibrator.Flags.FLAG_CANCEL_BY_APPOPS)
+ public void vibrate_thenDeniedAppOps_getsCancelled() throws Throwable {
+ mockVibrators(1);
+ VibratorManagerService service = createSystemReadyService();
+
+ var vib = vibrate(service,
+ VibrationEffect.createWaveform(new long[]{100, 100, 100, 100}, 0), RINGTONE_ATTRS);
+
+ assertTrue(waitUntil(s -> s.isVibrating(1), service, TEST_TIMEOUT_MILLIS));
+
+ when(mAppOpsManagerMock.checkAudioOpNoThrow(eq(AppOpsManager.OP_VIBRATE),
+ eq(AudioAttributes.USAGE_NOTIFICATION_RINGTONE), anyInt(), anyString()))
+ .thenReturn(AppOpsManager.MODE_IGNORED);
+
+ service.mAppOpsChangeListener.onOpChanged(AppOpsManager.OP_VIBRATE, null);
+
+ assertTrue(waitUntil(s -> vib.hasEnded(), service, TEST_TIMEOUT_MILLIS));
+
+ var statsInfoCaptor = ArgumentCaptor.forClass(VibrationStats.StatsInfo.class);
+ verify(mVibratorFrameworkStatsLoggerMock, timeout(TEST_TIMEOUT_MILLIS))
+ .writeVibrationReportedAsync(statsInfoCaptor.capture());
+
+ VibrationStats.StatsInfo touchMetrics = statsInfoCaptor.getAllValues().get(0);
+ assertEquals(Vibration.Status.CANCELLED_BY_APP_OPS.getProtoEnumValue(),
+ touchMetrics.status);
+ }
+
+ @Test
public void vibrate_withVibrationAttributes_usesCorrespondingAudioUsageInAppOpsManager() {
VibratorManagerService service = createSystemReadyService();
diff --git a/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
index c67d1ec..8b4d779 100644
--- a/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
@@ -30,6 +30,7 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+import static com.android.server.wm.ActivityRecord.State.STOPPED;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
@@ -245,6 +246,7 @@
assertTrue("Animation scheduled", backNavigationInfo.isPrepareRemoteAnimation());
// reset drawing status
+ testCase.recordBack.setState(STOPPED, "stopped");
backNavigationInfo.onBackNavigationFinished(false);
mBackNavigationController.clearBackAnimations();
makeWindowVisibleAndDrawn(testCase.recordFront.findMainWindow());
@@ -937,6 +939,7 @@
testCase.recordFront = record2;
testCase.windowBack = window1;
testCase.windowFront = window2;
+ record1.setState(STOPPED, "stopped");
return testCase;
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java b/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java
index d2494ff..fbc4c7b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java
@@ -172,14 +172,14 @@
@Test
public void testSurfaceOrigin_applied() {
mLetterbox.layout(new Rect(0, 0, 10, 10), new Rect(0, 1, 10, 10), new Point(1000, 2000));
- mLetterbox.applySurfaceChanges(mTransaction);
+ applySurfaceChanges();
verify(mTransaction).setPosition(mSurfaces.top, -1000, -2000);
}
@Test
public void testApplySurfaceChanges_setColor() {
mLetterbox.layout(new Rect(0, 0, 10, 10), new Rect(0, 1, 10, 10), new Point(1000, 2000));
- mLetterbox.applySurfaceChanges(mTransaction);
+ applySurfaceChanges();
verify(mTransaction).setColor(mSurfaces.top, new float[]{0, 0, 0});
@@ -187,7 +187,7 @@
assertTrue(mLetterbox.needsApplySurfaceChanges());
- mLetterbox.applySurfaceChanges(mTransaction);
+ applySurfaceChanges();
verify(mTransaction).setColor(mSurfaces.top, new float[]{0, 1, 0});
}
@@ -195,7 +195,7 @@
@Test
public void testNeedsApplySurfaceChanges_wallpaperBackgroundRequested() {
mLetterbox.layout(new Rect(0, 0, 10, 10), new Rect(0, 1, 10, 10), new Point(1000, 2000));
- mLetterbox.applySurfaceChanges(mTransaction);
+ applySurfaceChanges();
verify(mTransaction).setAlpha(mSurfaces.top, 1.0f);
assertFalse(mLetterbox.needsApplySurfaceChanges());
@@ -204,14 +204,14 @@
assertTrue(mLetterbox.needsApplySurfaceChanges());
- mLetterbox.applySurfaceChanges(mTransaction);
+ applySurfaceChanges();
verify(mTransaction).setAlpha(mSurfaces.fullWindowSurface, mDarkScrimAlpha);
}
@Test
public void testNeedsApplySurfaceChanges_setParentSurface() {
mLetterbox.layout(new Rect(0, 0, 10, 10), new Rect(0, 1, 10, 10), new Point(1000, 2000));
- mLetterbox.applySurfaceChanges(mTransaction);
+ applySurfaceChanges();
verify(mTransaction).reparent(mSurfaces.top, mParentSurface);
assertFalse(mLetterbox.needsApplySurfaceChanges());
@@ -220,14 +220,14 @@
assertTrue(mLetterbox.needsApplySurfaceChanges());
- mLetterbox.applySurfaceChanges(mTransaction);
+ applySurfaceChanges();
verify(mTransaction).reparent(mSurfaces.top, mParentSurface);
}
@Test
public void testApplySurfaceChanges_cornersNotRounded_surfaceFullWindowSurfaceNotCreated() {
mLetterbox.layout(new Rect(0, 0, 10, 10), new Rect(0, 1, 10, 10), new Point(1000, 2000));
- mLetterbox.applySurfaceChanges(mTransaction);
+ applySurfaceChanges();
assertNull(mSurfaces.fullWindowSurface);
}
@@ -236,7 +236,7 @@
public void testApplySurfaceChanges_cornersRounded_surfaceFullWindowSurfaceCreated() {
mAreCornersRounded = true;
mLetterbox.layout(new Rect(0, 0, 10, 10), new Rect(0, 1, 10, 10), new Point(1000, 2000));
- mLetterbox.applySurfaceChanges(mTransaction);
+ applySurfaceChanges();
assertNotNull(mSurfaces.fullWindowSurface);
}
@@ -245,7 +245,7 @@
public void testApplySurfaceChanges_wallpaperBackground_surfaceFullWindowSurfaceCreated() {
mHasWallpaperBackground = true;
mLetterbox.layout(new Rect(0, 0, 10, 10), new Rect(0, 1, 10, 10), new Point(1000, 2000));
- mLetterbox.applySurfaceChanges(mTransaction);
+ applySurfaceChanges();
assertNotNull(mSurfaces.fullWindowSurface);
}
@@ -254,7 +254,7 @@
public void testNotIntersectsOrFullyContains_cornersRounded() {
mAreCornersRounded = true;
mLetterbox.layout(new Rect(0, 0, 10, 10), new Rect(0, 1, 10, 10), new Point(0, 0));
- mLetterbox.applySurfaceChanges(mTransaction);
+ applySurfaceChanges();
assertTrue(mLetterbox.notIntersectsOrFullyContains(new Rect(1, 2, 9, 9)));
}
@@ -262,14 +262,19 @@
@Test
public void testSurfaceOrigin_changeCausesReapply() {
mLetterbox.layout(new Rect(0, 0, 10, 10), new Rect(0, 1, 10, 10), new Point(1000, 2000));
- mLetterbox.applySurfaceChanges(mTransaction);
+ applySurfaceChanges();
clearInvocations(mTransaction);
mLetterbox.layout(new Rect(0, 0, 10, 10), new Rect(0, 1, 10, 10), new Point(0, 0));
assertTrue(mLetterbox.needsApplySurfaceChanges());
- mLetterbox.applySurfaceChanges(mTransaction);
+ applySurfaceChanges();
verify(mTransaction).setPosition(mSurfaces.top, 0, 0);
}
+ private void applySurfaceChanges() {
+ mLetterbox.applySurfaceChanges(/* syncTransaction */ mTransaction,
+ /* pendingTransaction */ mTransaction);
+ }
+
class SurfaceControlMocker implements Supplier<SurfaceControl.Builder> {
private SurfaceControl.Builder mLeftBuilder;
public SurfaceControl left;
diff --git a/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java
index cd19449..0787052 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java
@@ -63,8 +63,8 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
-import static com.android.server.wm.LetterboxUiController.MIN_COUNT_TO_IGNORE_REQUEST_IN_LOOP;
-import static com.android.server.wm.LetterboxUiController.SET_ORIENTATION_REQUEST_COUNTER_TIMEOUT_MS;
+import static com.android.server.wm.AppCompatOrientationCapability.OrientationCapabilityState.MIN_COUNT_TO_IGNORE_REQUEST_IN_LOOP;
+import static com.android.server.wm.AppCompatOrientationCapability.OrientationCapabilityState.SET_ORIENTATION_REQUEST_COUNTER_TIMEOUT_MS;
import static com.android.window.flags.Flags.FLAG_CAMERA_COMPAT_FOR_FREEFORM;
import static org.junit.Assert.assertEquals;
@@ -156,7 +156,9 @@
public void testShouldIgnoreRequestedOrientation_activityRelaunching_returnsTrue() {
prepareActivityThatShouldIgnoreRequestedOrientationDuringRelaunch();
- assertTrue(mController.shouldIgnoreRequestedOrientation(SCREEN_ORIENTATION_UNSPECIFIED));
+ assertTrue(mActivity.mAppCompatController.getAppCompatCapability()
+ .getAppCompatOrientationCapability()
+ .shouldIgnoreRequestedOrientation(SCREEN_ORIENTATION_UNSPECIFIED));
}
@Test
@@ -176,14 +178,18 @@
doReturn(true).when(mDisplayContent.mDisplayRotationCompatPolicy)
.isTreatmentEnabledForActivity(eq(mActivity));
- assertTrue(mController.shouldIgnoreRequestedOrientation(SCREEN_ORIENTATION_UNSPECIFIED));
+ assertTrue(mActivity.mAppCompatController.getAppCompatCapability()
+ .getAppCompatOrientationCapability()
+ .shouldIgnoreRequestedOrientation(SCREEN_ORIENTATION_UNSPECIFIED));
}
@Test
public void testShouldIgnoreRequestedOrientation_overrideDisabled_returnsFalse() {
prepareActivityThatShouldIgnoreRequestedOrientationDuringRelaunch();
- assertFalse(mController.shouldIgnoreRequestedOrientation(SCREEN_ORIENTATION_UNSPECIFIED));
+ assertFalse(mActivity.mAppCompatController.getAppCompatCapability()
+ .getAppCompatOrientationCapability()
+ .shouldIgnoreRequestedOrientation(SCREEN_ORIENTATION_UNSPECIFIED));
}
@Test
@@ -195,7 +201,9 @@
mController = new LetterboxUiController(mWm, mActivity);
prepareActivityThatShouldIgnoreRequestedOrientationDuringRelaunch();
- assertTrue(mController.shouldIgnoreRequestedOrientation(SCREEN_ORIENTATION_UNSPECIFIED));
+ assertTrue(mActivity.mAppCompatController.getAppCompatCapability()
+ .getAppCompatOrientationCapability()
+ .shouldIgnoreRequestedOrientation(SCREEN_ORIENTATION_UNSPECIFIED));
}
@Test
@@ -209,7 +217,9 @@
mController = new LetterboxUiController(mWm, mActivity);
prepareActivityThatShouldIgnoreRequestedOrientationDuringRelaunch();
- assertFalse(mController.shouldIgnoreRequestedOrientation(SCREEN_ORIENTATION_UNSPECIFIED));
+ assertFalse(mActivity.mAppCompatController.getAppCompatCapability()
+ .getAppCompatOrientationCapability()
+ .shouldIgnoreRequestedOrientation(SCREEN_ORIENTATION_UNSPECIFIED));
}
@Test
@@ -315,7 +325,9 @@
doReturn(false).when(mLetterboxConfiguration)
.isPolicyForIgnoringRequestedOrientationEnabled();
- assertFalse(mController.shouldIgnoreRequestedOrientation(SCREEN_ORIENTATION_UNSPECIFIED));
+ assertFalse(mActivity.mAppCompatController.getAppCompatCapability()
+ .getAppCompatOrientationCapability()
+ .shouldIgnoreRequestedOrientation(SCREEN_ORIENTATION_UNSPECIFIED));
}
// shouldRefreshActivityForCameraCompat
@@ -522,8 +534,9 @@
final Rect opaqueBounds = new Rect(0, 0, 500, 300);
doReturn(opaqueBounds).when(mActivity).getBounds();
// Activity is translucent
- spyOn(mActivity.mTransparentPolicy);
- when(mActivity.mTransparentPolicy.isRunning()).thenReturn(true);
+ spyOn(mActivity.mAppCompatController.getTransparentPolicy());
+ when(mActivity.mAppCompatController.getTransparentPolicy()
+ .isRunning()).thenReturn(true);
// Makes requested sizes different
mainWindow.mRequestedWidth = opaqueBounds.width() - 1;
@@ -736,6 +749,7 @@
throws Exception {
mockThatProperty(PROPERTY_COMPAT_ALLOW_ORIENTATION_OVERRIDE, /* value */ false);
+ mActivity = setUpActivityWithComponent();
mController = new LetterboxUiController(mWm, mActivity);
mDisplayContent.setIgnoreOrientationRequest(true);
@@ -781,10 +795,14 @@
@EnableCompatChanges({OVERRIDE_ANY_ORIENTATION_TO_USER})
public void testOverrideOrientationIfNeeded_fullscreenAndUserOverrideEnabled_returnsUnchanged()
throws Exception {
- prepareActivityThatShouldApplyUserMinAspectRatioOverride();
+ doReturn(true).when(mLetterboxConfiguration).isUserAppAspectRatioSettingsEnabled();
+ mActivity = setUpActivityWithComponent();
+ spyOn(mActivity.mLetterboxUiController);
+ doReturn(USER_MIN_ASPECT_RATIO_3_2).when(mActivity.mLetterboxUiController)
+ .getUserMinAspectRatioOverrideCode();
- assertEquals(SCREEN_ORIENTATION_PORTRAIT, mController.overrideOrientationIfNeeded(
- /* candidate */ SCREEN_ORIENTATION_PORTRAIT));
+ assertEquals(SCREEN_ORIENTATION_PORTRAIT, mActivity.mLetterboxUiController
+ .overrideOrientationIfNeeded(/* candidate */ SCREEN_ORIENTATION_PORTRAIT));
}
@Test
@@ -852,6 +870,7 @@
throws Exception {
mockThatProperty(PROPERTY_COMPAT_ALLOW_ORIENTATION_OVERRIDE, /* value */ false);
+ mActivity = setUpActivityWithComponent();
mController = new LetterboxUiController(mWm, mActivity);
assertEquals(SCREEN_ORIENTATION_UNSPECIFIED, mController.overrideOrientationIfNeeded(
@@ -900,12 +919,14 @@
@Test
public void testOverrideOrientationIfNeeded_userFullscreenOverride_returnsUser() {
- spyOn(mController);
- doReturn(true).when(mController).shouldApplyUserFullscreenOverride();
+ spyOn(mActivity.mLetterboxUiController);
+ doReturn(true).when(mActivity.mLetterboxUiController)
+ .shouldApplyUserFullscreenOverride();
mDisplayContent.setIgnoreOrientationRequest(true);
- assertEquals(SCREEN_ORIENTATION_USER, mController.overrideOrientationIfNeeded(
- /* candidate */ SCREEN_ORIENTATION_UNSPECIFIED));
+ assertEquals(SCREEN_ORIENTATION_USER, mActivity.mAppCompatController
+ .getOrientationPolicy()
+ .overrideOrientationIfNeeded(/* candidate */ SCREEN_ORIENTATION_UNSPECIFIED));
}
@Test
@@ -961,12 +982,14 @@
@Test
@EnableCompatChanges({OVERRIDE_UNDEFINED_ORIENTATION_TO_PORTRAIT, OVERRIDE_ANY_ORIENTATION})
public void testOverrideOrientationIfNeeded_userFullScreenOverrideOverSystem_returnsUser() {
- spyOn(mController);
- doReturn(true).when(mController).shouldApplyUserFullscreenOverride();
+ spyOn(mActivity.mLetterboxUiController);
+ doReturn(true).when(mActivity.mLetterboxUiController)
+ .shouldApplyUserFullscreenOverride();
mDisplayContent.setIgnoreOrientationRequest(true);
- assertEquals(SCREEN_ORIENTATION_USER, mController.overrideOrientationIfNeeded(
- /* candidate */ SCREEN_ORIENTATION_PORTRAIT));
+ assertEquals(SCREEN_ORIENTATION_USER, mActivity.mAppCompatController
+ .getOrientationPolicy()
+ .overrideOrientationIfNeeded(/* candidate */ SCREEN_ORIENTATION_PORTRAIT));
}
@Test
@@ -991,18 +1014,19 @@
@Test
public void testOverrideOrientationIfNeeded_userAspectRatioApplied_unspecifiedOverridden() {
- spyOn(mController);
- doReturn(true).when(mController).shouldApplyUserMinAspectRatioOverride();
+ spyOn(mActivity.mLetterboxUiController);
+ doReturn(true).when(mActivity.mLetterboxUiController)
+ .shouldApplyUserMinAspectRatioOverride();
- assertEquals(SCREEN_ORIENTATION_PORTRAIT, mController.overrideOrientationIfNeeded(
- /* candidate */ SCREEN_ORIENTATION_UNSPECIFIED));
+ assertEquals(SCREEN_ORIENTATION_PORTRAIT, mActivity.mLetterboxUiController
+ .overrideOrientationIfNeeded(/* candidate */ SCREEN_ORIENTATION_UNSPECIFIED));
- assertEquals(SCREEN_ORIENTATION_PORTRAIT, mController.overrideOrientationIfNeeded(
- /* candidate */ SCREEN_ORIENTATION_LOCKED));
+ assertEquals(SCREEN_ORIENTATION_PORTRAIT, mActivity.mLetterboxUiController
+ .overrideOrientationIfNeeded(/* candidate */ SCREEN_ORIENTATION_LOCKED));
// unchanged if orientation is specified
- assertEquals(SCREEN_ORIENTATION_LANDSCAPE, mController.overrideOrientationIfNeeded(
- /* candidate */ SCREEN_ORIENTATION_LANDSCAPE));
+ assertEquals(SCREEN_ORIENTATION_LANDSCAPE, mActivity.mLetterboxUiController
+ .overrideOrientationIfNeeded(/* candidate */ SCREEN_ORIENTATION_LANDSCAPE));
}
@Test
@@ -1062,6 +1086,7 @@
prepareActivityThatShouldApplyUserMinAspectRatioOverride();
mockThatProperty(PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_OVERRIDE, /* value */ false);
+ mActivity = setUpActivityWithComponent();
mController = new LetterboxUiController(mWm, mActivity);
assertFalse(mController.shouldEnableUserAspectRatioSettings());
@@ -1344,6 +1369,8 @@
public void testshouldOverrideMinAspectRatio_propertyFalse_overrideEnabled_returnsFalse()
throws Exception {
mockThatProperty(PROPERTY_COMPAT_ALLOW_MIN_ASPECT_RATIO_OVERRIDE, /* value */ false);
+
+ mActivity = setUpActivityWithComponent();
mController = new LetterboxUiController(mWm, mActivity);
assertFalse(mController.shouldOverrideMinAspectRatio());
@@ -1472,6 +1499,8 @@
public void testshouldOverrideForceResizeApp_propertyFalse_overrideEnabled_returnsFalse()
throws Exception {
mockThatProperty(PROPERTY_COMPAT_ALLOW_RESIZEABLE_ACTIVITY_OVERRIDES, /* value */ false);
+
+ mActivity = setUpActivityWithComponent();
mController = new LetterboxUiController(mWm, mActivity);
assertFalse(mController.shouldOverrideForceResizeApp());
@@ -1528,6 +1557,8 @@
public void testshouldOverrideForceNonResizeApp_propertyFalse_overrideEnabled_returnsFalse()
throws Exception {
mockThatProperty(PROPERTY_COMPAT_ALLOW_RESIZEABLE_ACTIVITY_OVERRIDES, /* value */ false);
+
+ mActivity = setUpActivityWithComponent();
mController = new LetterboxUiController(mWm, mActivity);
assertFalse(mController.shouldOverrideForceNonResizeApp());
diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
index ac1aa20..3a85451 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -4271,6 +4271,27 @@
}
+ @Test
+ public void testInsetOverrideNotAppliedInFreeform() {
+ final int notchHeight = 100;
+ final DisplayContent display = new TestDisplayContent.Builder(mAtm, 1000, 2800)
+ .setNotch(notchHeight)
+ .build();
+ setUpApp(display);
+
+ // Simulate inset override for legacy app bound behaviour
+ mActivity.mResolveConfigHint.mUseOverrideInsetsForConfig = true;
+ // Set task as freeform
+ mTask.setWindowingMode(WindowConfiguration.WINDOWING_MODE_FREEFORM);
+ prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT);
+
+ Rect bounds = new Rect(mActivity.getWindowConfiguration().getBounds());
+ Rect appBounds = new Rect(mActivity.getWindowConfiguration().getAppBounds());
+ // App bounds should not include insets and should match bounds when in freeform.
+ assertEquals(new Rect(0, 0, 1000, 2800), appBounds);
+ assertEquals(new Rect(0, 0, 1000, 2800), bounds);
+ }
+
private void assertVerticalPositionForDifferentDisplayConfigsForLandscapeActivity(
float letterboxVerticalPositionMultiplier, Rect fixedOrientationLetterbox,
Rect sizeCompatUnscaled, Rect sizeCompatScaled) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/TransparentPolicyTest.java b/services/tests/wmtests/src/com/android/server/wm/TransparentPolicyTest.java
index 1d6e307..78cea95 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TransparentPolicyTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TransparentPolicyTest.java
@@ -332,7 +332,7 @@
mTask = task;
mActivityStack = new ActivityStackTest();
mActivityStack.pushActivity(opaqueActivity);
- spyOn(opaqueActivity.mTransparentPolicy);
+ spyOn(opaqueActivity.mAppCompatController.getTransparentPolicy());
}
void configureTopActivityAsEmbedded() {
@@ -360,7 +360,7 @@
if (addToTask) {
mTask.addChild(newActivity);
}
- spyOn(newActivity.mTransparentPolicy);
+ spyOn(newActivity.mAppCompatController.getTransparentPolicy());
mActivityStack.pushActivity(newActivity);
}
@@ -406,31 +406,34 @@
}
void checkTopActivityPolicyStateIsRunning() {
- assertTrue(mActivityStack.top().mTransparentPolicy.isRunning());
+ assertTrue(mActivityStack.top().mAppCompatController
+ .getTransparentPolicy().isRunning());
}
void checkTopActivityPolicyStateIsNotRunning() {
- assertFalse(mActivityStack.top().mTransparentPolicy.isRunning());
+ assertFalse(mActivityStack.top().mAppCompatController
+ .getTransparentPolicy().isRunning());
}
void checkTopActivityPolicyStopInvoked() {
- verify(mActivityStack.top().mTransparentPolicy).stop();
+ verify(mActivityStack.top().mAppCompatController.getTransparentPolicy()).stop();
}
void checkTopActivityPolicyStopNotInvoked() {
mActivityStack.applyToTop((activity) -> {
- verify(activity.mTransparentPolicy, never()).stop();
+ verify(activity.mAppCompatController.getTransparentPolicy(), never()).stop();
});
}
void checkTopActivityPolicyStartInvoked() {
mActivityStack.applyToTop((activity) -> {
- verify(activity.mTransparentPolicy).start();
+ verify(activity.mAppCompatController.getTransparentPolicy()).start();
});
}
void checkTopActivityPolicyStartNotInvoked() {
- verify(mActivityStack.top().mTransparentPolicy, never()).start();
+ verify(mActivityStack.top().mAppCompatController.getTransparentPolicy(),
+ never()).start();
}
void assertTrueOnActivity(int fromTop, Predicate<ActivityRecord> predicate) {
@@ -505,7 +508,7 @@
void clearInteractions() {
mActivityStack.applyToAll((activity) -> {
clearInvocations(activity);
- clearInvocations(activity.mTransparentPolicy);
+ clearInvocations(activity.mAppCompatController.getTransparentPolicy());
});
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
index 24ebad6..fcf7a3f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
@@ -78,7 +78,6 @@
import android.content.pm.ActivityInfo;
import android.graphics.Rect;
import android.os.Binder;
-import android.os.Bundle;
import android.os.IBinder;
import android.os.InputConfig;
import android.os.Process;
@@ -94,7 +93,6 @@
import android.util.MergedConfiguration;
import android.view.ContentRecordingSession;
import android.view.IWindow;
-import android.view.IWindowSession;
import android.view.InputChannel;
import android.view.InsetsSourceControl;
import android.view.InsetsState;
@@ -265,69 +263,7 @@
}
@Test
- public void testRelayoutExitingWindow_legacy() {
- mSetFlagsRule.disableFlags(Flags.FLAG_WINDOW_SESSION_RELAYOUT_INFO);
-
- final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, "appWin");
- final WindowSurfaceController surfaceController = mock(WindowSurfaceController.class);
- win.mWinAnimator.mSurfaceController = surfaceController;
- win.mWinAnimator.mDrawState = WindowStateAnimator.HAS_DRAWN;
- doReturn(true).when(surfaceController).hasSurface();
- spyOn(win.mTransitionController);
- doReturn(true).when(win.mTransitionController).isShellTransitionsEnabled();
- doReturn(true).when(win.mTransitionController).inTransition(
- eq(win.mActivityRecord));
- win.mViewVisibility = View.VISIBLE;
- win.mHasSurface = true;
- win.mActivityRecord.mAppStopped = true;
- mWm.mWindowMap.put(win.mClient.asBinder(), win);
- spyOn(mWm.mWindowPlacerLocked);
- // Skip unnecessary operations of relayout.
- doNothing().when(mWm.mWindowPlacerLocked).performSurfacePlacement(anyBoolean());
- final int w = 100;
- final int h = 200;
- final ClientWindowFrames outFrames = new ClientWindowFrames();
- final MergedConfiguration outConfig = new MergedConfiguration();
- final SurfaceControl outSurfaceControl = new SurfaceControl();
- final InsetsState outInsetsState = new InsetsState();
- final InsetsSourceControl.Array outControls = new InsetsSourceControl.Array();
- final Bundle outBundle = new Bundle();
- mWm.relayoutWindow(win.mSession, win.mClient, win.mAttrs, w, h, View.GONE, 0, 0, 0,
- outFrames, outConfig, outSurfaceControl, outInsetsState, outControls, outBundle);
- // The window is in transition, so its destruction is deferred.
- assertTrue(win.mAnimatingExit);
- assertFalse(win.mDestroying);
- assertTrue(win.mTransitionController.mAnimatingExitWindows.contains(win));
-
- win.mAnimatingExit = false;
- win.mViewVisibility = View.VISIBLE;
- win.mActivityRecord.setVisibleRequested(false);
- win.mActivityRecord.setVisible(false);
- mWm.relayoutWindow(win.mSession, win.mClient, win.mAttrs, w, h, View.GONE, 0, 0, 0,
- outFrames, outConfig, outSurfaceControl, outInsetsState, outControls, outBundle);
- // Because the window is already invisible, it doesn't need to apply exiting animation
- // and WMS#tryStartExitingAnimation() will destroy the surface directly.
- assertFalse(win.mAnimatingExit);
- assertFalse(win.mHasSurface);
- assertNull(win.mWinAnimator.mSurfaceController);
-
- // Invisible requested activity should not get the last config even if its view is visible.
- mWm.relayoutWindow(win.mSession, win.mClient, win.mAttrs, w, h, View.VISIBLE, 0, 0, 0,
- outFrames, outConfig, outSurfaceControl, outInsetsState, outControls, outBundle);
- assertEquals(0, outConfig.getMergedConfiguration().densityDpi);
- // Non activity window can still get the last config.
- win.mActivityRecord = null;
- win.fillClientWindowFramesAndConfiguration(outFrames, outConfig,
- null /* outActivityWindowInfo*/, false /* useLatestConfig */,
- true /* relayoutVisible */);
- assertEquals(win.getConfiguration().densityDpi,
- outConfig.getMergedConfiguration().densityDpi);
- }
-
- @Test
public void testRelayoutExitingWindow() {
- mSetFlagsRule.enableFlags(Flags.FLAG_WINDOW_SESSION_RELAYOUT_INFO);
-
final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, "appWin");
final WindowSurfaceController surfaceController = mock(WindowSurfaceController.class);
win.mWinAnimator.mSurfaceController = surfaceController;
@@ -483,15 +419,8 @@
win.mRelayoutSeq = 1;
seq = 2;
}
- if (Flags.windowSessionRelayoutInfo()) {
- mWm.relayoutWindow(win.mSession, win.mClient, newParams, 100, 200, View.VISIBLE, 0, seq,
- 0, new WindowRelayoutResult());
- } else {
- mWm.relayoutWindow(win.mSession, win.mClient, newParams, 100, 200, View.VISIBLE, 0, seq,
- 0, new ClientWindowFrames(), new MergedConfiguration(),
- new SurfaceControl(), new InsetsState(), new InsetsSourceControl.Array(),
- new Bundle());
- }
+ mWm.relayoutWindow(win.mSession, win.mClient, newParams, 100, 200, View.VISIBLE, 0, seq,
+ 0, new WindowRelayoutResult());
ArgumentCaptor<Integer> changedFlags = ArgumentCaptor.forClass(Integer.class);
ArgumentCaptor<Integer> changedPrivateFlags = ArgumentCaptor.forClass(Integer.class);
@@ -1364,70 +1293,8 @@
}
@Test
- public void testRelayout_appWindowSendActivityWindowInfo_legacy() {
- mSetFlagsRule.enableFlags(Flags.FLAG_ACTIVITY_WINDOW_INFO_FLAG);
- mSetFlagsRule.disableFlags(Flags.FLAG_WINDOW_SESSION_RELAYOUT_INFO);
-
- // Skip unnecessary operations of relayout.
- spyOn(mWm.mWindowPlacerLocked);
- doNothing().when(mWm.mWindowPlacerLocked).performSurfacePlacement(anyBoolean());
-
- final Task task = createTask(mDisplayContent);
- final WindowState win = createAppWindow(task, ACTIVITY_TYPE_STANDARD, "appWindow");
- mWm.mWindowMap.put(win.mClient.asBinder(), win);
-
- final int w = 100;
- final int h = 200;
- final ClientWindowFrames outFrames = new ClientWindowFrames();
- final MergedConfiguration outConfig = new MergedConfiguration();
- final SurfaceControl outSurfaceControl = new SurfaceControl();
- final InsetsState outInsetsState = new InsetsState();
- final InsetsSourceControl.Array outControls = new InsetsSourceControl.Array();
- final Bundle outBundle = new Bundle();
-
- final ActivityRecord activity = win.mActivityRecord;
- final ActivityWindowInfo expectedInfo = new ActivityWindowInfo();
- expectedInfo.set(true, new Rect(0, 0, 1000, 2000), new Rect(0, 0, 500, 2000));
- doReturn(expectedInfo).when(activity).getActivityWindowInfo();
- activity.setVisibleRequested(false);
- activity.setVisible(false);
-
- mWm.relayoutWindow(win.mSession, win.mClient, win.mAttrs, w, h, View.VISIBLE, 0, 0, 0,
- outFrames, outConfig, outSurfaceControl, outInsetsState, outControls, outBundle);
-
- // No latest reported value, so return empty when activity is invisible
- final ActivityWindowInfo activityWindowInfo = outBundle.getParcelable(
- IWindowSession.KEY_RELAYOUT_BUNDLE_ACTIVITY_WINDOW_INFO, ActivityWindowInfo.class);
- assertEquals(new ActivityWindowInfo(), activityWindowInfo);
-
- activity.setVisibleRequested(true);
- activity.setVisible(true);
-
- mWm.relayoutWindow(win.mSession, win.mClient, win.mAttrs, w, h, View.VISIBLE, 0, 0, 0,
- outFrames, outConfig, outSurfaceControl, outInsetsState, outControls, outBundle);
-
- // Report the latest when activity is visible.
- final ActivityWindowInfo activityWindowInfo2 = outBundle.getParcelable(
- IWindowSession.KEY_RELAYOUT_BUNDLE_ACTIVITY_WINDOW_INFO, ActivityWindowInfo.class);
- assertEquals(expectedInfo, activityWindowInfo2);
-
- expectedInfo.set(false, new Rect(0, 0, 1000, 2000), new Rect(0, 0, 1000, 2000));
- activity.setVisibleRequested(false);
- activity.setVisible(false);
-
- mWm.relayoutWindow(win.mSession, win.mClient, win.mAttrs, w, h, View.VISIBLE, 0, 0, 0,
- outFrames, outConfig, outSurfaceControl, outInsetsState, outControls, outBundle);
-
- // Report the last reported value when activity is invisible.
- final ActivityWindowInfo activityWindowInfo3 = outBundle.getParcelable(
- IWindowSession.KEY_RELAYOUT_BUNDLE_ACTIVITY_WINDOW_INFO, ActivityWindowInfo.class);
- assertEquals(activityWindowInfo2, activityWindowInfo3);
- }
-
- @Test
public void testRelayout_appWindowSendActivityWindowInfo() {
mSetFlagsRule.enableFlags(Flags.FLAG_ACTIVITY_WINDOW_INFO_FLAG);
- mSetFlagsRule.enableFlags(Flags.FLAG_WINDOW_SESSION_RELAYOUT_INFO);
// Skip unnecessary operations of relayout.
spyOn(mWm.mWindowPlacerLocked);
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index b152c3e..e13376b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -86,7 +86,6 @@
import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.Rect;
-import android.os.Bundle;
import android.os.IBinder;
import android.os.InputConfig;
import android.os.RemoteException;
@@ -114,7 +113,6 @@
import com.android.server.testutils.StubTransaction;
import com.android.server.wm.SensitiveContentPackages.PackageInfo;
-import com.android.window.flags.Flags;
import org.junit.After;
import org.junit.Test;
@@ -1369,67 +1367,7 @@
@SetupWindows(addWindows = {W_INPUT_METHOD})
@Test
- public void testImeTargetChangeListener_OnImeTargetOverlayVisibilityChanged_legacy() {
- mSetFlagsRule.disableFlags(Flags.FLAG_WINDOW_SESSION_RELAYOUT_INFO);
-
- final TestImeTargetChangeListener listener = new TestImeTargetChangeListener();
- mWm.mImeTargetChangeListener = listener;
-
- // Scenario 1: test addWindow/relayoutWindow to add Ime layering overlay window as visible.
- final WindowToken windowToken = createTestWindowToken(TYPE_APPLICATION_OVERLAY,
- mDisplayContent);
- final IWindow client = new TestIWindow();
- final Session session = getTestSession();
- final ClientWindowFrames outFrames = new ClientWindowFrames();
- final MergedConfiguration outConfig = new MergedConfiguration();
- final SurfaceControl outSurfaceControl = new SurfaceControl();
- final InsetsState outInsetsState = new InsetsState();
- final InsetsSourceControl.Array outControls = new InsetsSourceControl.Array();
- final Bundle outBundle = new Bundle();
- final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
- TYPE_APPLICATION_OVERLAY);
- params.setTitle("imeLayeringTargetOverlay");
- params.token = windowToken.token;
- params.flags = FLAG_NOT_FOCUSABLE | FLAG_ALT_FOCUSABLE_IM;
-
- mWm.addWindow(session, client, params, View.VISIBLE, DEFAULT_DISPLAY,
- 0 /* userUd */, WindowInsets.Type.defaultVisible(), null, new InsetsState(),
- new InsetsSourceControl.Array(), new Rect(), new float[1]);
- mWm.relayoutWindow(session, client, params, 100, 200, View.VISIBLE, 0, 0, 0,
- outFrames, outConfig, outSurfaceControl, outInsetsState, outControls, outBundle);
- waitHandlerIdle(mWm.mH);
-
- final WindowState imeLayeringTargetOverlay = mDisplayContent.getWindow(
- w -> w.mClient.asBinder() == client.asBinder());
- assertThat(imeLayeringTargetOverlay.isVisible()).isTrue();
- assertThat(listener.mImeTargetToken).isEqualTo(client.asBinder());
- assertThat(listener.mIsRemoved).isFalse();
- assertThat(listener.mIsVisibleForImeTargetOverlay).isTrue();
-
- // Scenario 2: test relayoutWindow to let the Ime layering target overlay window invisible.
- mWm.relayoutWindow(session, client, params, 100, 200, View.GONE, 0, 0, 0,
- outFrames, outConfig, outSurfaceControl, outInsetsState, outControls, outBundle);
- waitHandlerIdle(mWm.mH);
-
- assertThat(imeLayeringTargetOverlay.isVisible()).isFalse();
- assertThat(listener.mImeTargetToken).isEqualTo(client.asBinder());
- assertThat(listener.mIsRemoved).isFalse();
- assertThat(listener.mIsVisibleForImeTargetOverlay).isFalse();
-
- // Scenario 3: test removeWindow to remove the Ime layering target overlay window.
- mWm.removeClientToken(session, client.asBinder());
- waitHandlerIdle(mWm.mH);
-
- assertThat(listener.mImeTargetToken).isEqualTo(client.asBinder());
- assertThat(listener.mIsRemoved).isTrue();
- assertThat(listener.mIsVisibleForImeTargetOverlay).isFalse();
- }
-
- @SetupWindows(addWindows = {W_INPUT_METHOD})
- @Test
public void testImeTargetChangeListener_OnImeTargetOverlayVisibilityChanged() {
- mSetFlagsRule.enableFlags(Flags.FLAG_WINDOW_SESSION_RELAYOUT_INFO);
-
final TestImeTargetChangeListener listener = new TestImeTargetChangeListener();
mWm.mImeTargetChangeListener = listener;
diff --git a/telephony/java/android/telephony/VisualVoicemailSmsFilterSettings.java b/telephony/java/android/telephony/VisualVoicemailSmsFilterSettings.java
index eadb726..2b515c9 100644
--- a/telephony/java/android/telephony/VisualVoicemailSmsFilterSettings.java
+++ b/telephony/java/android/telephony/VisualVoicemailSmsFilterSettings.java
@@ -64,6 +64,14 @@
* @hide
*/
public static final int DEFAULT_DESTINATION_PORT = DESTINATION_PORT_ANY;
+ /**
+ * @hide
+ */
+ public static final int MAX_STRING_LENGTH = 256;
+ /**
+ * @hide
+ */
+ public static final int MAX_LIST_SIZE = 100;
/**
* Builder class for {@link VisualVoicemailSmsFilterSettings} objects.
@@ -82,11 +90,16 @@
/**
* Sets the client prefix for the visual voicemail SMS filter. The client prefix will appear
* at the start of a visual voicemail SMS message, followed by a colon(:).
+ * @throws IllegalArgumentException if the string length is greater than 256 characters
*/
public Builder setClientPrefix(String clientPrefix) {
if (clientPrefix == null) {
throw new IllegalArgumentException("Client prefix cannot be null");
}
+ if (clientPrefix.length() > MAX_STRING_LENGTH) {
+ throw new IllegalArgumentException("Client prefix cannot be greater than "
+ + MAX_STRING_LENGTH + " characters");
+ }
mClientPrefix = clientPrefix;
return this;
}
@@ -95,11 +108,25 @@
* Sets the originating number allow list for the visual voicemail SMS filter. If the list
* is not null only the SMS messages from a number in the list can be considered as a visual
* voicemail SMS. Otherwise, messages from any address will be considered.
+ * @throws IllegalArgumentException if the size of the originatingNumbers list is greater
+ * than 100 elements
+ * @throws IllegalArgumentException if an element within the originatingNumbers list has
+ * a string length greater than 256
*/
public Builder setOriginatingNumbers(List<String> originatingNumbers) {
if (originatingNumbers == null) {
throw new IllegalArgumentException("Originating numbers cannot be null");
}
+ if (originatingNumbers.size() > MAX_LIST_SIZE) {
+ throw new IllegalArgumentException("The originatingNumbers list size cannot be"
+ + " greater than " + MAX_STRING_LENGTH + " elements");
+ }
+ for (String num : originatingNumbers) {
+ if (num != null && num.length() > MAX_STRING_LENGTH) {
+ throw new IllegalArgumentException("Numbers within the originatingNumbers list"
+ + " cannot be greater than" + MAX_STRING_LENGTH + " characters");
+ }
+ }
mOriginatingNumbers = originatingNumbers;
return this;
}
diff --git a/tests/BootImageProfileTest/OWNERS b/tests/BootImageProfileTest/OWNERS
index 57303e7..64775f8 100644
--- a/tests/BootImageProfileTest/OWNERS
+++ b/tests/BootImageProfileTest/OWNERS
@@ -1,4 +1 @@
-calin@google.com
-ngeoffray@google.com
-vmarko@google.com
-yawanng@google.com
+include platform/art:main:/OWNERS_boot_profile
diff --git a/tests/TrustTests/src/android/trust/test/GrantAndRevokeTrustTest.kt b/tests/TrustTests/src/android/trust/test/GrantAndRevokeTrustTest.kt
index d0e5626..0c3c7e2 100644
--- a/tests/TrustTests/src/android/trust/test/GrantAndRevokeTrustTest.kt
+++ b/tests/TrustTests/src/android/trust/test/GrantAndRevokeTrustTest.kt
@@ -17,9 +17,6 @@
package android.trust.test
import android.content.pm.PackageManager
-import android.platform.test.annotations.RequiresFlagsDisabled
-import android.platform.test.annotations.RequiresFlagsEnabled
-import android.platform.test.flag.junit.DeviceFlagsValueProvider
import android.service.trust.GrantTrustResult
import android.trust.BaseTrustAgentService
import android.trust.TrustTestActivity
@@ -58,7 +55,6 @@
.around(ScreenLockRule())
.around(lockStateTrackingRule)
.around(trustAgentRule)
- .around(DeviceFlagsValueProvider.createCheckFlagsRule())
@Before
fun manageTrust() {
@@ -93,7 +89,6 @@
}
@Test
- @RequiresFlagsEnabled(android.security.Flags.FLAG_FIX_UNLOCKED_DEVICE_REQUIRED_KEYS_V2)
fun grantCannotActivelyUnlockDevice() {
// On automotive, trust agents can actively unlock the device.
assumeFalse(packageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE))
@@ -120,24 +115,6 @@
}
@Test
- @RequiresFlagsDisabled(android.security.Flags.FLAG_FIX_UNLOCKED_DEVICE_REQUIRED_KEYS_V2)
- fun grantCouldCauseWrongDeviceLockedStateDueToBug() {
- // On automotive, trust agents can actively unlock the device.
- assumeFalse(packageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE))
-
- // Verify that b/296464083 exists. That is, when the device is locked
- // and a trust agent grants trust, the deviceLocked state incorrectly
- // becomes false even though the device correctly remains locked.
- uiDevice.sleep()
- lockStateTrackingRule.assertLocked()
- trustAgentRule.agent.grantTrust(GRANT_MESSAGE, 10000, 0) {}
- uiDevice.wakeUp()
- uiDevice.sleep()
- await()
- lockStateTrackingRule.assertUnlockedButNotReally()
- }
-
- @Test
fun grantDoesNotCallBack() {
val callback = mock<(GrantTrustResult) -> Unit>()
trustAgentRule.agent.grantTrust(GRANT_MESSAGE, 0, 0, callback)
diff --git a/tests/TrustTests/src/android/trust/test/lib/LockStateTrackingRule.kt b/tests/TrustTests/src/android/trust/test/lib/LockStateTrackingRule.kt
index 0121809..80d7947 100644
--- a/tests/TrustTests/src/android/trust/test/lib/LockStateTrackingRule.kt
+++ b/tests/TrustTests/src/android/trust/test/lib/LockStateTrackingRule.kt
@@ -64,13 +64,6 @@
wait("not trusted") { trustState.trusted == false }
}
- // TODO(b/299298338) remove this when removing FLAG_FIX_UNLOCKED_DEVICE_REQUIRED_KEYS_V2
- fun assertUnlockedButNotReally() {
- wait("device unlocked") { !keyguardManager.isDeviceLocked }
- wait("not trusted") { trustState.trusted == false }
- wait("keyguard locked") { windowManager.isKeyguardLocked }
- }
-
fun assertUnlockedAndTrusted() {
wait("device unlocked") { !keyguardManager.isDeviceLocked }
wait("trusted") { trustState.trusted == true }
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AppInfo.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AppInfo.java
index 129733e..f397225 100644
--- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AppInfo.java
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AppInfo.java
@@ -25,99 +25,42 @@
/** AppInfo representation */
public class AppInfo implements AslMarshallable {
- private final String mTitle;
- private final String mDescription;
- private final Boolean mContainsAds;
- private final Boolean mObeyAps;
- private final Boolean mAdsFingerprinting;
- private final Boolean mSecurityFingerprinting;
+ private final Boolean mApsCompliant;
private final String mPrivacyPolicy;
- private final List<String> mSecurityEndpoints;
private final List<String> mFirstPartyEndpoints;
private final List<String> mServiceProviderEndpoints;
- private final String mCategory;
- private final String mEmail;
- private final String mWebsite;
public AppInfo(
- String title,
- String description,
- Boolean containsAds,
- Boolean obeyAps,
- Boolean adsFingerprinting,
- Boolean securityFingerprinting,
+ Boolean apsCompliant,
String privacyPolicy,
- List<String> securityEndpoints,
List<String> firstPartyEndpoints,
- List<String> serviceProviderEndpoints,
- String category,
- String email,
- String website) {
- this.mTitle = title;
- this.mDescription = description;
- this.mContainsAds = containsAds;
- this.mObeyAps = obeyAps;
- this.mAdsFingerprinting = adsFingerprinting;
- this.mSecurityFingerprinting = securityFingerprinting;
+ List<String> serviceProviderEndpoints) {
+ this.mApsCompliant = apsCompliant;
this.mPrivacyPolicy = privacyPolicy;
- this.mSecurityEndpoints = securityEndpoints;
this.mFirstPartyEndpoints = firstPartyEndpoints;
this.mServiceProviderEndpoints = serviceProviderEndpoints;
- this.mCategory = category;
- this.mEmail = email;
- this.mWebsite = website;
}
/** Creates an on-device DOM element from the {@link SafetyLabels}. */
@Override
public List<Element> toOdDomElements(Document doc) {
Element appInfoEle = XmlUtils.createPbundleEleWithName(doc, XmlUtils.OD_NAME_APP_INFO);
- if (this.mTitle != null) {
- appInfoEle.appendChild(XmlUtils.createOdStringEle(doc, XmlUtils.OD_NAME_TITLE, mTitle));
- }
- if (this.mDescription != null) {
- appInfoEle.appendChild(
- XmlUtils.createOdStringEle(doc, XmlUtils.OD_NAME_DESCRIPTION, mDescription));
- }
- if (this.mContainsAds != null) {
- appInfoEle.appendChild(
- XmlUtils.createOdBooleanEle(doc, XmlUtils.OD_NAME_CONTAINS_ADS, mContainsAds));
- }
- if (this.mObeyAps != null) {
- appInfoEle.appendChild(
- XmlUtils.createOdBooleanEle(doc, XmlUtils.OD_NAME_OBEY_APS, mObeyAps));
- }
- if (this.mAdsFingerprinting != null) {
+ if (this.mApsCompliant != null) {
appInfoEle.appendChild(
XmlUtils.createOdBooleanEle(
- doc, XmlUtils.OD_NAME_ADS_FINGERPRINTING, mAdsFingerprinting));
- }
- if (this.mSecurityFingerprinting != null) {
- appInfoEle.appendChild(
- XmlUtils.createOdBooleanEle(
- doc,
- XmlUtils.OD_NAME_SECURITY_FINGERPRINTING,
- mSecurityFingerprinting));
+ doc, XmlUtils.OD_NAME_APS_COMPLIANT, mApsCompliant));
}
if (this.mPrivacyPolicy != null) {
appInfoEle.appendChild(
XmlUtils.createOdStringEle(
doc, XmlUtils.OD_NAME_PRIVACY_POLICY, mPrivacyPolicy));
}
- if (this.mSecurityEndpoints != null) {
- appInfoEle.appendChild(
- XmlUtils.createOdArray(
- doc,
- XmlUtils.OD_TAG_STRING_ARRAY,
- XmlUtils.OD_NAME_SECURITY_ENDPOINT,
- mSecurityEndpoints));
- }
if (this.mFirstPartyEndpoints != null) {
appInfoEle.appendChild(
XmlUtils.createOdArray(
doc,
XmlUtils.OD_TAG_STRING_ARRAY,
- XmlUtils.OD_NAME_FIRST_PARTY_ENDPOINT,
+ XmlUtils.OD_NAME_FIRST_PARTY_ENDPOINTS,
mFirstPartyEndpoints));
}
if (this.mServiceProviderEndpoints != null) {
@@ -125,21 +68,9 @@
XmlUtils.createOdArray(
doc,
XmlUtils.OD_TAG_STRING_ARRAY,
- XmlUtils.OD_NAME_SERVICE_PROVIDER_ENDPOINT,
+ XmlUtils.OD_NAME_SERVICE_PROVIDER_ENDPOINTS,
mServiceProviderEndpoints));
}
- if (this.mCategory != null) {
- appInfoEle.appendChild(
- XmlUtils.createOdStringEle(doc, XmlUtils.OD_NAME_CATEGORY, this.mCategory));
- }
- if (this.mEmail != null) {
- appInfoEle.appendChild(
- XmlUtils.createOdStringEle(doc, XmlUtils.OD_NAME_EMAIL, this.mEmail));
- }
- if (this.mWebsite != null) {
- appInfoEle.appendChild(
- XmlUtils.createOdStringEle(doc, XmlUtils.OD_NAME_WEBSITE, this.mWebsite));
- }
return XmlUtils.listOf(appInfoEle);
}
@@ -147,54 +78,28 @@
@Override
public List<Element> toHrDomElements(Document doc) {
Element appInfoEle = doc.createElement(XmlUtils.HR_TAG_APP_INFO);
- if (this.mTitle != null) {
- appInfoEle.setAttribute(XmlUtils.HR_ATTR_TITLE, this.mTitle);
- }
- if (this.mDescription != null) {
- appInfoEle.setAttribute(XmlUtils.HR_ATTR_DESCRIPTION, this.mDescription);
- }
- if (this.mContainsAds != null) {
+ if (this.mApsCompliant != null) {
appInfoEle.setAttribute(
- XmlUtils.HR_ATTR_CONTAINS_ADS, String.valueOf(this.mContainsAds));
- }
- if (this.mObeyAps != null) {
- appInfoEle.setAttribute(XmlUtils.HR_ATTR_OBEY_APS, String.valueOf(this.mObeyAps));
- }
- if (this.mAdsFingerprinting != null) {
- appInfoEle.setAttribute(
- XmlUtils.HR_ATTR_ADS_FINGERPRINTING, String.valueOf(this.mAdsFingerprinting));
- }
- if (this.mSecurityFingerprinting != null) {
- appInfoEle.setAttribute(
- XmlUtils.HR_ATTR_SECURITY_FINGERPRINTING,
- String.valueOf(this.mSecurityFingerprinting));
+ XmlUtils.HR_ATTR_APS_COMPLIANT, String.valueOf(this.mApsCompliant));
}
if (this.mPrivacyPolicy != null) {
appInfoEle.setAttribute(XmlUtils.HR_ATTR_PRIVACY_POLICY, this.mPrivacyPolicy);
}
- if (this.mSecurityEndpoints != null) {
- appInfoEle.setAttribute(
- XmlUtils.HR_ATTR_SECURITY_ENDPOINTS, String.join("|", this.mSecurityEndpoints));
- }
+
if (this.mFirstPartyEndpoints != null) {
- appInfoEle.setAttribute(
- XmlUtils.HR_ATTR_FIRST_PARTY_ENDPOINTS,
- String.join("|", this.mFirstPartyEndpoints));
+ appInfoEle.appendChild(
+ XmlUtils.createHrArray(
+ doc, XmlUtils.HR_TAG_FIRST_PARTY_ENDPOINTS, mFirstPartyEndpoints));
}
+
if (this.mServiceProviderEndpoints != null) {
- appInfoEle.setAttribute(
- XmlUtils.HR_ATTR_SERVICE_PROVIDER_ENDPOINTS,
- String.join("|", this.mServiceProviderEndpoints));
+ appInfoEle.appendChild(
+ XmlUtils.createHrArray(
+ doc,
+ XmlUtils.HR_TAG_SERVICE_PROVIDER_ENDPOINTS,
+ mServiceProviderEndpoints));
}
- if (this.mCategory != null) {
- appInfoEle.setAttribute(XmlUtils.HR_ATTR_CATEGORY, this.mCategory);
- }
- if (this.mEmail != null) {
- appInfoEle.setAttribute(XmlUtils.HR_ATTR_EMAIL, this.mEmail);
- }
- if (this.mWebsite != null) {
- appInfoEle.setAttribute(XmlUtils.HR_ATTR_WEBSITE, this.mWebsite);
- }
+
return XmlUtils.listOf(appInfoEle);
}
}
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AppInfoFactory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AppInfoFactory.java
index c506961..6ad2027 100644
--- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AppInfoFactory.java
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AppInfoFactory.java
@@ -35,43 +35,19 @@
return null;
}
- String title = XmlUtils.getStringAttr(appInfoEle, XmlUtils.HR_ATTR_TITLE, true);
- String description = XmlUtils.getStringAttr(appInfoEle, XmlUtils.HR_ATTR_DESCRIPTION, true);
- Boolean containsAds = XmlUtils.getBoolAttr(appInfoEle, XmlUtils.HR_ATTR_CONTAINS_ADS, true);
- Boolean obeyAps = XmlUtils.getBoolAttr(appInfoEle, XmlUtils.HR_ATTR_OBEY_APS, true);
- Boolean adsFingerprinting =
- XmlUtils.getBoolAttr(appInfoEle, XmlUtils.HR_ATTR_ADS_FINGERPRINTING, true);
- Boolean securityFingerprinting =
- XmlUtils.getBoolAttr(appInfoEle, XmlUtils.HR_ATTR_SECURITY_FINGERPRINTING, true);
+ Boolean apsCompliant =
+ XmlUtils.getBoolAttr(appInfoEle, XmlUtils.HR_ATTR_APS_COMPLIANT, true);
String privacyPolicy =
XmlUtils.getStringAttr(appInfoEle, XmlUtils.HR_ATTR_PRIVACY_POLICY, true);
- List<String> securityEndpoints =
- XmlUtils.getPipelineSplitAttr(
- appInfoEle, XmlUtils.HR_ATTR_SECURITY_ENDPOINTS, true);
List<String> firstPartyEndpoints =
- XmlUtils.getPipelineSplitAttr(
- appInfoEle, XmlUtils.HR_ATTR_FIRST_PARTY_ENDPOINTS, true);
+ XmlUtils.getHrItemsAsStrings(
+ appInfoEle, XmlUtils.HR_TAG_FIRST_PARTY_ENDPOINTS, true);
List<String> serviceProviderEndpoints =
- XmlUtils.getPipelineSplitAttr(
- appInfoEle, XmlUtils.HR_ATTR_SERVICE_PROVIDER_ENDPOINTS, true);
- String category = XmlUtils.getStringAttr(appInfoEle, XmlUtils.HR_ATTR_CATEGORY, true);
- String email = XmlUtils.getStringAttr(appInfoEle, XmlUtils.HR_ATTR_EMAIL, true);
- String website = XmlUtils.getStringAttr(appInfoEle, XmlUtils.HR_ATTR_WEBSITE, false);
+ XmlUtils.getHrItemsAsStrings(
+ appInfoEle, XmlUtils.HR_TAG_SERVICE_PROVIDER_ENDPOINTS, true);
return new AppInfo(
- title,
- description,
- containsAds,
- obeyAps,
- adsFingerprinting,
- securityFingerprinting,
- privacyPolicy,
- securityEndpoints,
- firstPartyEndpoints,
- serviceProviderEndpoints,
- category,
- email,
- website);
+ apsCompliant, privacyPolicy, firstPartyEndpoints, serviceProviderEndpoints);
}
/** Creates an {@link AslMarshallableFactory} from on-device DOM elements */
@@ -83,42 +59,17 @@
return null;
}
- String title = XmlUtils.getOdStringEle(appInfoEle, XmlUtils.OD_NAME_TITLE, true);
- String description =
- XmlUtils.getOdStringEle(appInfoEle, XmlUtils.OD_NAME_DESCRIPTION, true);
- Boolean containsAds =
- XmlUtils.getOdBoolEle(appInfoEle, XmlUtils.OD_NAME_CONTAINS_ADS, true);
- Boolean obeyAps = XmlUtils.getOdBoolEle(appInfoEle, XmlUtils.OD_NAME_OBEY_APS, true);
- Boolean adsFingerprinting =
- XmlUtils.getOdBoolEle(appInfoEle, XmlUtils.OD_NAME_ADS_FINGERPRINTING, true);
- Boolean securityFingerprinting =
- XmlUtils.getOdBoolEle(appInfoEle, XmlUtils.OD_NAME_SECURITY_FINGERPRINTING, true);
+ Boolean apsCompliant =
+ XmlUtils.getOdBoolEle(appInfoEle, XmlUtils.OD_NAME_APS_COMPLIANT, true);
String privacyPolicy =
XmlUtils.getOdStringEle(appInfoEle, XmlUtils.OD_NAME_PRIVACY_POLICY, true);
- List<String> securityEndpoints =
- XmlUtils.getOdStringArray(appInfoEle, XmlUtils.OD_NAME_SECURITY_ENDPOINT, true);
List<String> firstPartyEndpoints =
- XmlUtils.getOdStringArray(appInfoEle, XmlUtils.OD_NAME_FIRST_PARTY_ENDPOINT, true);
+ XmlUtils.getOdStringArray(appInfoEle, XmlUtils.OD_NAME_FIRST_PARTY_ENDPOINTS, true);
List<String> serviceProviderEndpoints =
XmlUtils.getOdStringArray(
- appInfoEle, XmlUtils.OD_NAME_SERVICE_PROVIDER_ENDPOINT, true);
- String category = XmlUtils.getOdStringEle(appInfoEle, XmlUtils.OD_NAME_CATEGORY, true);
- String email = XmlUtils.getOdStringEle(appInfoEle, XmlUtils.OD_NAME_EMAIL, true);
- String website = XmlUtils.getOdStringEle(appInfoEle, XmlUtils.OD_NAME_WEBSITE, false);
+ appInfoEle, XmlUtils.OD_NAME_SERVICE_PROVIDER_ENDPOINTS, true);
return new AppInfo(
- title,
- description,
- containsAds,
- obeyAps,
- adsFingerprinting,
- securityFingerprinting,
- privacyPolicy,
- securityEndpoints,
- firstPartyEndpoints,
- serviceProviderEndpoints,
- category,
- email,
- website);
+ apsCompliant, privacyPolicy, firstPartyEndpoints, serviceProviderEndpoints);
}
}
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DeveloperInfo.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DeveloperInfo.java
deleted file mode 100644
index 94fad96..0000000
--- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DeveloperInfo.java
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.asllib.marshallable;
-
-import com.android.asllib.util.XmlUtils;
-
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-
-import java.util.List;
-
-/** DeveloperInfo representation */
-public class DeveloperInfo implements AslMarshallable {
- public enum DeveloperRelationship {
- OEM(0),
- ODM(1),
- SOC(2),
- OTA(3),
- CARRIER(4),
- AOSP(5),
- OTHER(6);
-
- private final int mValue;
-
- DeveloperRelationship(int value) {
- this.mValue = value;
- }
-
- /** Get the int value associated with the DeveloperRelationship. */
- public int getValue() {
- return mValue;
- }
-
- /** Get the DeveloperRelationship associated with the int value. */
- public static DeveloperInfo.DeveloperRelationship forValue(int value) {
- for (DeveloperInfo.DeveloperRelationship e : values()) {
- if (e.getValue() == value) {
- return e;
- }
- }
- throw new IllegalArgumentException("No DeveloperRelationship enum for value: " + value);
- }
-
- /** Get the DeveloperRelationship associated with the human-readable String. */
- public static DeveloperInfo.DeveloperRelationship forString(String s) {
- for (DeveloperInfo.DeveloperRelationship e : values()) {
- if (e.toString().equals(s)) {
- return e;
- }
- }
- throw new IllegalArgumentException("No DeveloperRelationship enum for str: " + s);
- }
-
- /** Human-readable String representation of DeveloperRelationship. */
- public String toString() {
- return this.name().toLowerCase();
- }
- }
-
- private final String mName;
- private final String mEmail;
- private final String mAddress;
- private final String mCountryRegion;
- private final DeveloperRelationship mDeveloperRelationship;
- private final String mWebsite;
- private final String mAppDeveloperRegistryId;
-
- public DeveloperInfo(
- String name,
- String email,
- String address,
- String countryRegion,
- DeveloperRelationship developerRelationship,
- String website,
- String appDeveloperRegistryId) {
- this.mName = name;
- this.mEmail = email;
- this.mAddress = address;
- this.mCountryRegion = countryRegion;
- this.mDeveloperRelationship = developerRelationship;
- this.mWebsite = website;
- this.mAppDeveloperRegistryId = appDeveloperRegistryId;
- }
-
- /** Creates an on-device DOM element from the {@link SafetyLabels}. */
- @Override
- public List<Element> toOdDomElements(Document doc) {
- Element developerInfoEle =
- XmlUtils.createPbundleEleWithName(doc, XmlUtils.OD_NAME_DEVELOPER_INFO);
- if (mName != null) {
- developerInfoEle.appendChild(
- XmlUtils.createOdStringEle(doc, XmlUtils.OD_NAME_NAME, mName));
- }
- if (mEmail != null) {
- developerInfoEle.appendChild(
- XmlUtils.createOdStringEle(doc, XmlUtils.OD_NAME_EMAIL, mEmail));
- }
- if (mAddress != null) {
- developerInfoEle.appendChild(
- XmlUtils.createOdStringEle(doc, XmlUtils.OD_NAME_ADDRESS, mAddress));
- }
- if (mCountryRegion != null) {
- developerInfoEle.appendChild(
- XmlUtils.createOdStringEle(
- doc, XmlUtils.OD_NAME_COUNTRY_REGION, mCountryRegion));
- }
- if (mDeveloperRelationship != null) {
- developerInfoEle.appendChild(
- XmlUtils.createOdLongEle(
- doc,
- XmlUtils.OD_NAME_DEVELOPER_RELATIONSHIP,
- mDeveloperRelationship.getValue()));
- }
- if (mWebsite != null) {
- developerInfoEle.appendChild(
- XmlUtils.createOdStringEle(doc, XmlUtils.OD_NAME_WEBSITE, mWebsite));
- }
- if (mAppDeveloperRegistryId != null) {
- developerInfoEle.appendChild(
- XmlUtils.createOdStringEle(
- doc,
- XmlUtils.OD_NAME_APP_DEVELOPER_REGISTRY_ID,
- mAppDeveloperRegistryId));
- }
-
- return XmlUtils.listOf(developerInfoEle);
- }
-
- /** Creates the human-readable DOM elements from the AslMarshallable Java Object. */
- @Override
- public List<Element> toHrDomElements(Document doc) {
- Element developerInfoEle = doc.createElement(XmlUtils.HR_TAG_DEVELOPER_INFO);
- if (mName != null) {
- developerInfoEle.setAttribute(XmlUtils.HR_ATTR_NAME, mName);
- }
- if (mEmail != null) {
- developerInfoEle.setAttribute(XmlUtils.HR_ATTR_EMAIL, mEmail);
- }
- if (mAddress != null) {
- developerInfoEle.setAttribute(XmlUtils.HR_ATTR_ADDRESS, mAddress);
- }
- if (mCountryRegion != null) {
- developerInfoEle.setAttribute(XmlUtils.HR_ATTR_COUNTRY_REGION, mCountryRegion);
- }
- if (mDeveloperRelationship != null) {
- developerInfoEle.setAttribute(
- XmlUtils.HR_ATTR_DEVELOPER_RELATIONSHIP, mDeveloperRelationship.toString());
- }
- if (mWebsite != null) {
- developerInfoEle.setAttribute(XmlUtils.HR_ATTR_WEBSITE, mWebsite);
- }
- if (mAppDeveloperRegistryId != null) {
- developerInfoEle.setAttribute(
- XmlUtils.HR_ATTR_APP_DEVELOPER_REGISTRY_ID, mAppDeveloperRegistryId);
- }
-
- return XmlUtils.listOf(developerInfoEle);
- }
-}
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DeveloperInfoFactory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DeveloperInfoFactory.java
deleted file mode 100644
index 0f3b41c..0000000
--- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DeveloperInfoFactory.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.asllib.marshallable;
-
-import com.android.asllib.util.AslgenUtil;
-import com.android.asllib.util.MalformedXmlException;
-import com.android.asllib.util.XmlUtils;
-
-import org.w3c.dom.Element;
-
-import java.util.List;
-
-public class DeveloperInfoFactory implements AslMarshallableFactory<DeveloperInfo> {
-
- /** Creates a {@link DeveloperInfo} from the human-readable DOM element. */
- @Override
- public DeveloperInfo createFromHrElements(List<Element> elements) throws MalformedXmlException {
- Element developerInfoEle = XmlUtils.getSingleElement(elements);
- if (developerInfoEle == null) {
- AslgenUtil.logI("No DeveloperInfo found in hr format.");
- return null;
- }
- String name = XmlUtils.getStringAttr(developerInfoEle, XmlUtils.HR_ATTR_NAME, true);
- String email = XmlUtils.getStringAttr(developerInfoEle, XmlUtils.HR_ATTR_EMAIL, true);
- String address = XmlUtils.getStringAttr(developerInfoEle, XmlUtils.HR_ATTR_ADDRESS, true);
- String countryRegion =
- XmlUtils.getStringAttr(developerInfoEle, XmlUtils.HR_ATTR_COUNTRY_REGION, true);
- DeveloperInfo.DeveloperRelationship developerRelationship =
- DeveloperInfo.DeveloperRelationship.forString(
- XmlUtils.getStringAttr(
- developerInfoEle, XmlUtils.HR_ATTR_DEVELOPER_RELATIONSHIP, true));
- String website = XmlUtils.getStringAttr(developerInfoEle, XmlUtils.HR_ATTR_WEBSITE, false);
- String appDeveloperRegistryId =
- XmlUtils.getStringAttr(
- developerInfoEle, XmlUtils.HR_ATTR_APP_DEVELOPER_REGISTRY_ID, false);
-
- return new DeveloperInfo(
- name,
- email,
- address,
- countryRegion,
- developerRelationship,
- website,
- appDeveloperRegistryId);
- }
-
- /** Creates an {@link AslMarshallableFactory} from on-device DOM elements */
- @Override
- public DeveloperInfo createFromOdElements(List<Element> elements) throws MalformedXmlException {
- Element developerInfoEle = XmlUtils.getSingleElement(elements);
- if (developerInfoEle == null) {
- AslgenUtil.logI("No DeveloperInfo found in od format.");
- return null;
- }
- String name = XmlUtils.getOdStringEle(developerInfoEle, XmlUtils.OD_NAME_NAME, true);
- String email = XmlUtils.getOdStringEle(developerInfoEle, XmlUtils.OD_NAME_EMAIL, true);
- String address = XmlUtils.getOdStringEle(developerInfoEle, XmlUtils.OD_NAME_ADDRESS, true);
- String countryRegion =
- XmlUtils.getOdStringEle(developerInfoEle, XmlUtils.OD_NAME_COUNTRY_REGION, true);
- DeveloperInfo.DeveloperRelationship developerRelationship =
- DeveloperInfo.DeveloperRelationship.forValue(
- (int)
- (long)
- XmlUtils.getOdLongEle(
- developerInfoEle,
- XmlUtils.OD_NAME_DEVELOPER_RELATIONSHIP,
- true));
- String website = XmlUtils.getOdStringEle(developerInfoEle, XmlUtils.OD_NAME_WEBSITE, false);
- String appDeveloperRegistryId =
- XmlUtils.getOdStringEle(
- developerInfoEle, XmlUtils.OD_NAME_APP_DEVELOPER_REGISTRY_ID, false);
-
- return new DeveloperInfo(
- name,
- email,
- address,
- countryRegion,
- developerRelationship,
- website,
- appDeveloperRegistryId);
- }
-}
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SafetyLabels.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SafetyLabels.java
index 6af8071..2a4e130 100644
--- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SafetyLabels.java
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SafetyLabels.java
@@ -25,21 +25,10 @@
/** Safety Label representation containing zero or more {@link DataCategory} for data shared */
public class SafetyLabels implements AslMarshallable {
-
- private final Long mVersion;
private final DataLabels mDataLabels;
- private final SecurityLabels mSecurityLabels;
- private final ThirdPartyVerification mThirdPartyVerification;
- public SafetyLabels(
- Long version,
- DataLabels dataLabels,
- SecurityLabels securityLabels,
- ThirdPartyVerification thirdPartyVerification) {
- this.mVersion = version;
+ public SafetyLabels(DataLabels dataLabels) {
this.mDataLabels = dataLabels;
- this.mSecurityLabels = securityLabels;
- this.mThirdPartyVerification = thirdPartyVerification;
}
/** Returns the data label for the safety label */
@@ -47,27 +36,14 @@
return mDataLabels;
}
- /** Gets the version of the {@link SafetyLabels}. */
- public Long getVersion() {
- return mVersion;
- }
-
/** Creates an on-device DOM element from the {@link SafetyLabels}. */
@Override
public List<Element> toOdDomElements(Document doc) {
Element safetyLabelsEle =
XmlUtils.createPbundleEleWithName(doc, XmlUtils.OD_NAME_SAFETY_LABELS);
- safetyLabelsEle.appendChild(
- XmlUtils.createOdLongEle(doc, XmlUtils.OD_NAME_VERSION, mVersion));
if (mDataLabels != null) {
XmlUtils.appendChildren(safetyLabelsEle, mDataLabels.toOdDomElements(doc));
}
- if (mSecurityLabels != null) {
- XmlUtils.appendChildren(safetyLabelsEle, mSecurityLabels.toOdDomElements(doc));
- }
- if (mThirdPartyVerification != null) {
- XmlUtils.appendChildren(safetyLabelsEle, mThirdPartyVerification.toOdDomElements(doc));
- }
return XmlUtils.listOf(safetyLabelsEle);
}
@@ -75,17 +51,10 @@
@Override
public List<Element> toHrDomElements(Document doc) {
Element safetyLabelsEle = doc.createElement(XmlUtils.HR_TAG_SAFETY_LABELS);
- safetyLabelsEle.setAttribute(XmlUtils.HR_ATTR_VERSION, String.valueOf(mVersion));
if (mDataLabels != null) {
XmlUtils.appendChildren(safetyLabelsEle, mDataLabels.toHrDomElements(doc));
}
- if (mSecurityLabels != null) {
- XmlUtils.appendChildren(safetyLabelsEle, mSecurityLabels.toHrDomElements(doc));
- }
- if (mThirdPartyVerification != null) {
- XmlUtils.appendChildren(safetyLabelsEle, mThirdPartyVerification.toHrDomElements(doc));
- }
return XmlUtils.listOf(safetyLabelsEle);
}
}
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SafetyLabelsFactory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SafetyLabelsFactory.java
index 2644b43..2738337 100644
--- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SafetyLabelsFactory.java
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SafetyLabelsFactory.java
@@ -34,7 +34,6 @@
AslgenUtil.logI("No SafetyLabels found in hr format.");
return null;
}
- long version = XmlUtils.tryGetVersion(safetyLabelsEle);
DataLabels dataLabels =
new DataLabelsFactory()
@@ -44,23 +43,7 @@
safetyLabelsEle,
XmlUtils.HR_TAG_DATA_LABELS,
false)));
- SecurityLabels securityLabels =
- new SecurityLabelsFactory()
- .createFromHrElements(
- XmlUtils.listOf(
- XmlUtils.getSingleChildElement(
- safetyLabelsEle,
- XmlUtils.HR_TAG_SECURITY_LABELS,
- false)));
- ThirdPartyVerification thirdPartyVerification =
- new ThirdPartyVerificationFactory()
- .createFromHrElements(
- XmlUtils.listOf(
- XmlUtils.getSingleChildElement(
- safetyLabelsEle,
- XmlUtils.HR_TAG_THIRD_PARTY_VERIFICATION,
- false)));
- return new SafetyLabels(version, dataLabels, securityLabels, thirdPartyVerification);
+ return new SafetyLabels(dataLabels);
}
/** Creates an {@link AslMarshallableFactory} from on-device DOM elements */
@@ -71,7 +54,6 @@
AslgenUtil.logI("No SafetyLabels found in od format.");
return null;
}
- Long version = XmlUtils.getOdLongEle(safetyLabelsEle, XmlUtils.OD_NAME_VERSION, true);
DataLabels dataLabels =
new DataLabelsFactory()
@@ -81,22 +63,7 @@
safetyLabelsEle,
XmlUtils.OD_NAME_DATA_LABELS,
false)));
- SecurityLabels securityLabels =
- new SecurityLabelsFactory()
- .createFromOdElements(
- XmlUtils.listOf(
- XmlUtils.getOdPbundleWithName(
- safetyLabelsEle,
- XmlUtils.OD_NAME_SECURITY_LABELS,
- false)));
- ThirdPartyVerification thirdPartyVerification =
- new ThirdPartyVerificationFactory()
- .createFromOdElements(
- XmlUtils.listOf(
- XmlUtils.getOdPbundleWithName(
- safetyLabelsEle,
- XmlUtils.OD_NAME_THIRD_PARTY_VERIFICATION,
- false)));
- return new SafetyLabels(version, dataLabels, securityLabels, thirdPartyVerification);
+
+ return new SafetyLabels(dataLabels);
}
}
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/TransparencyInfo.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/TransparencyInfo.java
index 6a8700a..9f789f0 100644
--- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/TransparencyInfo.java
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/TransparencyInfo.java
@@ -23,22 +23,14 @@
import java.util.List;
-/** TransparencyInfo representation containing {@link DeveloperInfo} and {@link AppInfo} */
+/** TransparencyInfo representation containing {@link AppInfo} */
public class TransparencyInfo implements AslMarshallable {
-
- private final DeveloperInfo mDeveloperInfo;
private final AppInfo mAppInfo;
- public TransparencyInfo(DeveloperInfo developerInfo, AppInfo appInfo) {
- this.mDeveloperInfo = developerInfo;
+ public TransparencyInfo(AppInfo appInfo) {
this.mAppInfo = appInfo;
}
- /** Gets the {@link DeveloperInfo} of the {@link TransparencyInfo}. */
- public DeveloperInfo getDeveloperInfo() {
- return mDeveloperInfo;
- }
-
/** Gets the {@link AppInfo} of the {@link TransparencyInfo}. */
public AppInfo getAppInfo() {
return mAppInfo;
@@ -49,9 +41,6 @@
public List<Element> toOdDomElements(Document doc) {
Element transparencyInfoEle =
XmlUtils.createPbundleEleWithName(doc, XmlUtils.OD_NAME_TRANSPARENCY_INFO);
- if (mDeveloperInfo != null) {
- XmlUtils.appendChildren(transparencyInfoEle, mDeveloperInfo.toOdDomElements(doc));
- }
if (mAppInfo != null) {
XmlUtils.appendChildren(transparencyInfoEle, mAppInfo.toOdDomElements(doc));
}
@@ -62,9 +51,6 @@
@Override
public List<Element> toHrDomElements(Document doc) {
Element transparencyInfoEle = doc.createElement(XmlUtils.HR_TAG_TRANSPARENCY_INFO);
- if (mDeveloperInfo != null) {
- XmlUtils.appendChildren(transparencyInfoEle, mDeveloperInfo.toHrDomElements(doc));
- }
if (mAppInfo != null) {
XmlUtils.appendChildren(transparencyInfoEle, mAppInfo.toHrDomElements(doc));
}
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/TransparencyInfoFactory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/TransparencyInfoFactory.java
index 94c5640..40f2872 100644
--- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/TransparencyInfoFactory.java
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/TransparencyInfoFactory.java
@@ -36,18 +36,11 @@
return null;
}
- Element developerInfoEle =
- XmlUtils.getSingleChildElement(
- transparencyInfoEle, XmlUtils.HR_TAG_DEVELOPER_INFO, false);
- DeveloperInfo developerInfo =
- new DeveloperInfoFactory().createFromHrElements(XmlUtils.listOf(developerInfoEle));
-
Element appInfoEle =
- XmlUtils.getSingleChildElement(
- transparencyInfoEle, XmlUtils.HR_TAG_APP_INFO, false);
+ XmlUtils.getSingleChildElement(transparencyInfoEle, XmlUtils.HR_TAG_APP_INFO, true);
AppInfo appInfo = new AppInfoFactory().createFromHrElements(XmlUtils.listOf(appInfoEle));
- return new TransparencyInfo(developerInfo, appInfo);
+ return new TransparencyInfo(appInfo);
}
/** Creates an {@link AslMarshallableFactory} from on-device DOM elements */
@@ -60,17 +53,10 @@
return null;
}
- Element developerInfoEle =
- XmlUtils.getOdPbundleWithName(
- transparencyInfoEle, XmlUtils.OD_NAME_DEVELOPER_INFO, false);
- DeveloperInfo developerInfo =
- new DeveloperInfoFactory().createFromOdElements(XmlUtils.listOf(developerInfoEle));
-
Element appInfoEle =
- XmlUtils.getOdPbundleWithName(
- transparencyInfoEle, XmlUtils.OD_NAME_APP_INFO, false);
+ XmlUtils.getOdPbundleWithName(transparencyInfoEle, XmlUtils.OD_NAME_APP_INFO, true);
AppInfo appInfo = new AppInfoFactory().createFromOdElements(XmlUtils.listOf(appInfoEle));
- return new TransparencyInfo(developerInfo, appInfo);
+ return new TransparencyInfo(appInfo);
}
}
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/util/XmlUtils.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/util/XmlUtils.java
index 97cbc39..26b5639 100644
--- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/util/XmlUtils.java
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/util/XmlUtils.java
@@ -42,6 +42,7 @@
public static final String HR_TAG_DATA_COLLECTED = "data-collected";
public static final String HR_TAG_DATA_COLLECTED_EPHEMERAL = "data-collected-ephemeral";
public static final String HR_TAG_DATA_SHARED = "data-shared";
+ public static final String HR_TAG_ITEM = "item";
public static final String HR_ATTR_NAME = "name";
public static final String HR_ATTR_EMAIL = "email";
public static final String HR_ATTR_ADDRESS = "address";
@@ -64,12 +65,13 @@
public static final String HR_ATTR_DESCRIPTION = "description";
public static final String HR_ATTR_CONTAINS_ADS = "containsAds";
public static final String HR_ATTR_OBEY_APS = "obeyAps";
+ public static final String HR_ATTR_APS_COMPLIANT = "apsCompliant";
public static final String HR_ATTR_ADS_FINGERPRINTING = "adsFingerprinting";
public static final String HR_ATTR_SECURITY_FINGERPRINTING = "securityFingerprinting";
public static final String HR_ATTR_PRIVACY_POLICY = "privacyPolicy";
public static final String HR_ATTR_SECURITY_ENDPOINTS = "securityEndpoints";
- public static final String HR_ATTR_FIRST_PARTY_ENDPOINTS = "firstPartyEndpoints";
- public static final String HR_ATTR_SERVICE_PROVIDER_ENDPOINTS = "serviceProviderEndpoints";
+ public static final String HR_TAG_FIRST_PARTY_ENDPOINTS = "first-party-endpoints";
+ public static final String HR_TAG_SERVICE_PROVIDER_ENDPOINTS = "service-provider-endpoints";
public static final String HR_ATTR_CATEGORY = "category";
public static final String OD_TAG_BUNDLE = "bundle";
@@ -98,12 +100,13 @@
public static final String OD_NAME_DESCRIPTION = "description";
public static final String OD_NAME_CONTAINS_ADS = "contains_ads";
public static final String OD_NAME_OBEY_APS = "obey_aps";
+ public static final String OD_NAME_APS_COMPLIANT = "aps_compliant";
public static final String OD_NAME_ADS_FINGERPRINTING = "ads_fingerprinting";
public static final String OD_NAME_SECURITY_FINGERPRINTING = "security_fingerprinting";
public static final String OD_NAME_PRIVACY_POLICY = "privacy_policy";
- public static final String OD_NAME_SECURITY_ENDPOINT = "security_endpoint";
- public static final String OD_NAME_FIRST_PARTY_ENDPOINT = "first_party_endpoint";
- public static final String OD_NAME_SERVICE_PROVIDER_ENDPOINT = "service_provider_endpoint";
+ public static final String OD_NAME_SECURITY_ENDPOINT = "security_endpoints";
+ public static final String OD_NAME_FIRST_PARTY_ENDPOINTS = "first_party_endpoints";
+ public static final String OD_NAME_SERVICE_PROVIDER_ENDPOINTS = "service_provider_endpoints";
public static final String OD_NAME_CATEGORY = "category";
public static final String OD_NAME_VERSION = "version";
public static final String OD_NAME_URL = "url";
@@ -237,7 +240,18 @@
return ele;
}
- /** Create OD style array DOM Element, which can represent any time but is stored as Strings. */
+ /** Create HR style array DOM Element. */
+ public static Element createHrArray(Document doc, String arrayTagName, List<String> arrayVals) {
+ Element arrEle = doc.createElement(arrayTagName);
+ for (String s : arrayVals) {
+ Element itemEle = doc.createElement(XmlUtils.HR_TAG_ITEM);
+ itemEle.setTextContent(s);
+ arrEle.appendChild(itemEle);
+ }
+ return arrEle;
+ }
+
+ /** Create OD style array DOM Element, which can represent any type but is stored as Strings. */
public static Element createOdArray(
Document doc, String arrayTag, String arrayName, List<String> arrayVals) {
Element arrEle = doc.createElement(arrayTag);
@@ -456,6 +470,32 @@
return ints;
}
+ /** Gets human-readable style String array. */
+ public static List<String> getHrItemsAsStrings(
+ Element parent, String elementName, boolean required) throws MalformedXmlException {
+
+ List<Element> arrayEles = XmlUtils.getChildrenByTagName(parent, elementName);
+ if (arrayEles.size() > 1) {
+ throw new MalformedXmlException(
+ String.format(
+ "Found more than one %s in %s.", elementName, parent.getTagName()));
+ }
+ if (arrayEles.isEmpty()) {
+ if (required) {
+ throw new MalformedXmlException(
+ String.format("Found no %s in %s.", elementName, parent.getTagName()));
+ }
+ return null;
+ }
+ Element arrayEle = arrayEles.get(0);
+ List<Element> itemEles = XmlUtils.getChildrenByTagName(arrayEle, XmlUtils.HR_TAG_ITEM);
+ List<String> strs = new ArrayList<String>();
+ for (Element itemEle : itemEles) {
+ strs.add(itemEle.getTextContent());
+ }
+ return strs;
+ }
+
/** Gets on-device style String array. */
public static List<String> getOdStringArray(Element ele, String nameName, boolean required)
throws MalformedXmlException {
diff --git a/tools/app_metadata_bundles/src/test/java/com/android/asllib/AllTests.java b/tools/app_metadata_bundles/src/test/java/com/android/asllib/AllTests.java
index dbeeb49..14e65e5 100644
--- a/tools/app_metadata_bundles/src/test/java/com/android/asllib/AllTests.java
+++ b/tools/app_metadata_bundles/src/test/java/com/android/asllib/AllTests.java
@@ -20,11 +20,8 @@
import com.android.asllib.marshallable.AppInfoTest;
import com.android.asllib.marshallable.DataLabelsTest;
import com.android.asllib.marshallable.DataTypeEqualityTest;
-import com.android.asllib.marshallable.DeveloperInfoTest;
import com.android.asllib.marshallable.SafetyLabelsTest;
-import com.android.asllib.marshallable.SecurityLabelsTest;
import com.android.asllib.marshallable.SystemAppSafetyLabelTest;
-import com.android.asllib.marshallable.ThirdPartyVerificationTest;
import com.android.asllib.marshallable.TransparencyInfoTest;
import org.junit.runner.RunWith;
@@ -35,14 +32,10 @@
AslgenTests.class,
AndroidSafetyLabelTest.class,
AppInfoTest.class,
- // DataCategoryTest.class,
DataLabelsTest.class,
DataTypeEqualityTest.class,
- DeveloperInfoTest.class,
SafetyLabelsTest.class,
- SecurityLabelsTest.class,
SystemAppSafetyLabelTest.class,
- ThirdPartyVerificationTest.class,
TransparencyInfoTest.class
})
public class AllTests {}
diff --git a/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/AppInfoTest.java b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/AppInfoTest.java
index 9e91c6f..d823c48 100644
--- a/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/AppInfoTest.java
+++ b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/AppInfoTest.java
@@ -20,6 +20,7 @@
import com.android.asllib.testutils.TestUtils;
import com.android.asllib.util.MalformedXmlException;
+import com.android.asllib.util.XmlUtils;
import org.junit.Before;
import org.junit.Test;
@@ -34,35 +35,15 @@
private static final String APP_INFO_HR_PATH = "com/android/asllib/appinfo/hr";
private static final String APP_INFO_OD_PATH = "com/android/asllib/appinfo/od";
public static final List<String> REQUIRED_FIELD_NAMES =
- List.of(
- "title",
- "description",
- "containsAds",
- "obeyAps",
- "adsFingerprinting",
- "securityFingerprinting",
- "privacyPolicy",
- "securityEndpoints",
- "firstPartyEndpoints",
- "serviceProviderEndpoints",
- "category",
- "email");
+ List.of("apsCompliant", "privacyPolicy");
public static final List<String> REQUIRED_FIELD_NAMES_OD =
- List.of(
- "title",
- "description",
- "contains_ads",
- "obey_aps",
- "ads_fingerprinting",
- "security_fingerprinting",
- "privacy_policy",
- "security_endpoint",
- "first_party_endpoint",
- "service_provider_endpoint",
- "category",
- "email");
- public static final List<String> OPTIONAL_FIELD_NAMES = List.of("website");
- public static final List<String> OPTIONAL_FIELD_NAMES_OD = List.of("website");
+ List.of("aps_compliant", "privacy_policy");
+ public static final List<String> REQUIRED_CHILD_NAMES =
+ List.of("first-party-endpoints", "service-provider-endpoints");
+ public static final List<String> REQUIRED_CHILD_NAMES_OD =
+ List.of("first_party_endpoints", "service_provider_endpoints");
+ public static final List<String> OPTIONAL_FIELD_NAMES = List.of();
+ public static final List<String> OPTIONAL_FIELD_NAMES_OD = List.of();
private static final String ALL_FIELDS_VALID_FILE_NAME = "all-fields-valid.xml";
@@ -110,6 +91,34 @@
}
}
+ /** Tests missing required child fails. */
+ @Test
+ public void testMissingRequiredChild() throws Exception {
+ System.out.println("Starting testMissingRequiredFields");
+ for (String reqChildName : REQUIRED_CHILD_NAMES) {
+ System.out.println("testing missing required child hr: " + reqChildName);
+ var appInfoEle =
+ TestUtils.getElementsFromResource(
+ Paths.get(APP_INFO_HR_PATH, ALL_FIELDS_VALID_FILE_NAME));
+ var child = XmlUtils.getChildrenByTagName(appInfoEle.get(0), reqChildName).get(0);
+ appInfoEle.get(0).removeChild(child);
+ assertThrows(
+ MalformedXmlException.class,
+ () -> new AppInfoFactory().createFromHrElements(appInfoEle));
+ }
+
+ for (String reqField : REQUIRED_CHILD_NAMES_OD) {
+ System.out.println("testing missing required child od: " + reqField);
+ var appInfoEle =
+ TestUtils.getElementsFromResource(
+ Paths.get(APP_INFO_OD_PATH, ALL_FIELDS_VALID_FILE_NAME));
+ TestUtils.removeOdChildEleWithName(appInfoEle.get(0), reqField);
+ assertThrows(
+ MalformedXmlException.class,
+ () -> new AppInfoFactory().createFromOdElements(appInfoEle));
+ }
+ }
+
/** Tests missing optional fields passes. */
@Test
public void testMissingOptionalFields() throws Exception {
diff --git a/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/DeveloperInfoTest.java b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/DeveloperInfoTest.java
deleted file mode 100644
index 72e8d65..0000000
--- a/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/DeveloperInfoTest.java
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.asllib.marshallable;
-
-import static org.junit.Assert.assertThrows;
-
-import com.android.asllib.testutils.TestUtils;
-import com.android.asllib.util.MalformedXmlException;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-import java.nio.file.Paths;
-import java.util.List;
-
-@RunWith(JUnit4.class)
-public class DeveloperInfoTest {
- private static final String DEVELOPER_INFO_HR_PATH = "com/android/asllib/developerinfo/hr";
- private static final String DEVELOPER_INFO_OD_PATH = "com/android/asllib/developerinfo/od";
- public static final List<String> REQUIRED_FIELD_NAMES =
- List.of("address", "countryRegion", "email", "name", "relationship");
- public static final List<String> REQUIRED_FIELD_NAMES_OD =
- List.of("address", "country_region", "email", "name", "relationship");
- public static final List<String> OPTIONAL_FIELD_NAMES = List.of("website", "registryId");
- public static final List<String> OPTIONAL_FIELD_NAMES_OD =
- List.of("website", "app_developer_registry_id");
-
- private static final String ALL_FIELDS_VALID_FILE_NAME = "all-fields-valid.xml";
-
- /** Logic for setting up tests (empty if not yet needed). */
- public static void main(String[] params) throws Exception {}
-
- @Before
- public void setUp() throws Exception {
- System.out.println("set up.");
- }
-
- /** Test for all fields valid. */
- @Test
- public void testAllFieldsValid() throws Exception {
- System.out.println("starting testAllFieldsValid.");
- testHrToOdDeveloperInfo(ALL_FIELDS_VALID_FILE_NAME);
- testOdToHrDeveloperInfo(ALL_FIELDS_VALID_FILE_NAME);
- }
-
- /** Tests missing required fields fails. */
- @Test
- public void testMissingRequiredFields() throws Exception {
- System.out.println("Starting testMissingRequiredFields");
- for (String reqField : REQUIRED_FIELD_NAMES) {
- System.out.println("testing missing required field: " + reqField);
- var developerInfoEle =
- TestUtils.getElementsFromResource(
- Paths.get(DEVELOPER_INFO_HR_PATH, ALL_FIELDS_VALID_FILE_NAME));
- developerInfoEle.get(0).removeAttribute(reqField);
-
- assertThrows(
- MalformedXmlException.class,
- () -> new DeveloperInfoFactory().createFromHrElements(developerInfoEle));
- }
-
- for (String reqField : REQUIRED_FIELD_NAMES_OD) {
- System.out.println("testing missing required field od: " + reqField);
- var developerInfoEle =
- TestUtils.getElementsFromResource(
- Paths.get(DEVELOPER_INFO_OD_PATH, ALL_FIELDS_VALID_FILE_NAME));
- TestUtils.removeOdChildEleWithName(developerInfoEle.get(0), reqField);
-
- assertThrows(
- MalformedXmlException.class,
- () -> new DeveloperInfoFactory().createFromOdElements(developerInfoEle));
- }
- }
-
- /** Tests missing optional fields passes. */
- @Test
- public void testMissingOptionalFields() throws Exception {
- for (String optField : OPTIONAL_FIELD_NAMES) {
- var developerInfoEle =
- TestUtils.getElementsFromResource(
- Paths.get(DEVELOPER_INFO_HR_PATH, ALL_FIELDS_VALID_FILE_NAME));
- developerInfoEle.get(0).removeAttribute(optField);
- DeveloperInfo developerInfo =
- new DeveloperInfoFactory().createFromHrElements(developerInfoEle);
- developerInfo.toOdDomElements(TestUtils.document());
- }
-
- for (String optField : OPTIONAL_FIELD_NAMES_OD) {
- var developerInfoEle =
- TestUtils.getElementsFromResource(
- Paths.get(DEVELOPER_INFO_OD_PATH, ALL_FIELDS_VALID_FILE_NAME));
- TestUtils.removeOdChildEleWithName(developerInfoEle.get(0), optField);
- DeveloperInfo developerInfo =
- new DeveloperInfoFactory().createFromOdElements(developerInfoEle);
- developerInfo.toHrDomElements(TestUtils.document());
- }
- }
-
- private void testHrToOdDeveloperInfo(String fileName) throws Exception {
- TestUtils.testHrToOd(
- TestUtils.document(),
- new DeveloperInfoFactory(),
- DEVELOPER_INFO_HR_PATH,
- DEVELOPER_INFO_OD_PATH,
- fileName);
- }
-
- private void testOdToHrDeveloperInfo(String fileName) throws Exception {
- TestUtils.testOdToHr(
- TestUtils.document(),
- new DeveloperInfoFactory(),
- DEVELOPER_INFO_OD_PATH,
- DEVELOPER_INFO_HR_PATH,
- fileName);
- }
-}
diff --git a/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/SafetyLabelsTest.java b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/SafetyLabelsTest.java
index bba6b54..19d1626 100644
--- a/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/SafetyLabelsTest.java
+++ b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/SafetyLabelsTest.java
@@ -28,26 +28,14 @@
private static final String SAFETY_LABELS_HR_PATH = "com/android/asllib/safetylabels/hr";
private static final String SAFETY_LABELS_OD_PATH = "com/android/asllib/safetylabels/od";
- private static final String MISSING_VERSION_FILE_NAME = "missing-version.xml";
private static final String VALID_EMPTY_FILE_NAME = "valid-empty.xml";
private static final String WITH_DATA_LABELS_FILE_NAME = "with-data-labels.xml";
- private static final String WITH_SECURITY_LABELS_FILE_NAME = "with-security-labels.xml";
- private static final String WITH_THIRD_PARTY_VERIFICATION_FILE_NAME =
- "with-third-party-verification.xml";
@Before
public void setUp() throws Exception {
System.out.println("set up.");
}
- /** Test for safety labels missing version. */
- @Test
- public void testSafetyLabelsMissingVersion() throws Exception {
- System.out.println("starting testSafetyLabelsMissingVersion.");
- hrToOdExpectException(MISSING_VERSION_FILE_NAME);
- odToHrExpectException(MISSING_VERSION_FILE_NAME);
- }
-
/** Test for safety labels valid empty. */
@Test
public void testSafetyLabelsValidEmptyFile() throws Exception {
@@ -64,22 +52,6 @@
testOdToHrSafetyLabels(WITH_DATA_LABELS_FILE_NAME);
}
- /** Test for safety labels with security labels. */
- @Test
- public void testSafetyLabelsWithSecurityLabels() throws Exception {
- System.out.println("starting testSafetyLabelsWithSecurityLabels.");
- testHrToOdSafetyLabels(WITH_SECURITY_LABELS_FILE_NAME);
- testOdToHrSafetyLabels(WITH_SECURITY_LABELS_FILE_NAME);
- }
-
- /** Test for safety labels with third party verification. */
- @Test
- public void testSafetyLabelsWithThirdPartyVerification() throws Exception {
- System.out.println("starting testSafetyLabelsWithThirdPartyVerification.");
- testHrToOdSafetyLabels(WITH_THIRD_PARTY_VERIFICATION_FILE_NAME);
- testOdToHrSafetyLabels(WITH_THIRD_PARTY_VERIFICATION_FILE_NAME);
- }
-
private void hrToOdExpectException(String fileName) {
TestUtils.hrToOdExpectException(new SafetyLabelsFactory(), SAFETY_LABELS_HR_PATH, fileName);
}
diff --git a/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/SecurityLabelsTest.java b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/SecurityLabelsTest.java
deleted file mode 100644
index a940bc6..0000000
--- a/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/SecurityLabelsTest.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.asllib.marshallable;
-
-
-import com.android.asllib.testutils.TestUtils;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-import java.nio.file.Paths;
-import java.util.List;
-
-@RunWith(JUnit4.class)
-public class SecurityLabelsTest {
- private static final String SECURITY_LABELS_HR_PATH = "com/android/asllib/securitylabels/hr";
- private static final String SECURITY_LABELS_OD_PATH = "com/android/asllib/securitylabels/od";
-
- public static final List<String> OPTIONAL_FIELD_NAMES =
- List.of("isDataDeletable", "isDataEncrypted");
- public static final List<String> OPTIONAL_FIELD_NAMES_OD =
- List.of("is_data_deletable", "is_data_encrypted");
-
- private static final String ALL_FIELDS_VALID_FILE_NAME = "all-fields-valid.xml";
-
- /** Logic for setting up tests (empty if not yet needed). */
- public static void main(String[] params) throws Exception {}
-
- @Before
- public void setUp() throws Exception {
- System.out.println("set up.");
- }
-
- /** Test for all fields valid. */
- @Test
- public void testAllFieldsValid() throws Exception {
- System.out.println("starting testAllFieldsValid.");
- testHrToOdSecurityLabels(ALL_FIELDS_VALID_FILE_NAME);
- testOdToHrSecurityLabels(ALL_FIELDS_VALID_FILE_NAME);
- }
-
- /** Tests missing optional fields passes. */
- @Test
- public void testMissingOptionalFields() throws Exception {
- for (String optField : OPTIONAL_FIELD_NAMES) {
- var ele =
- TestUtils.getElementsFromResource(
- Paths.get(SECURITY_LABELS_HR_PATH, ALL_FIELDS_VALID_FILE_NAME));
- ele.get(0).removeAttribute(optField);
- SecurityLabels securityLabels = new SecurityLabelsFactory().createFromHrElements(ele);
- securityLabels.toOdDomElements(TestUtils.document());
- }
- for (String optField : OPTIONAL_FIELD_NAMES_OD) {
- var ele =
- TestUtils.getElementsFromResource(
- Paths.get(SECURITY_LABELS_OD_PATH, ALL_FIELDS_VALID_FILE_NAME));
- TestUtils.removeOdChildEleWithName(ele.get(0), optField);
- SecurityLabels securityLabels = new SecurityLabelsFactory().createFromOdElements(ele);
- securityLabels.toHrDomElements(TestUtils.document());
- }
- }
-
- private void testHrToOdSecurityLabels(String fileName) throws Exception {
- TestUtils.testHrToOd(
- TestUtils.document(),
- new SecurityLabelsFactory(),
- SECURITY_LABELS_HR_PATH,
- SECURITY_LABELS_OD_PATH,
- fileName);
- }
-
- private void testOdToHrSecurityLabels(String fileName) throws Exception {
- TestUtils.testOdToHr(
- TestUtils.document(),
- new SecurityLabelsFactory(),
- SECURITY_LABELS_OD_PATH,
- SECURITY_LABELS_HR_PATH,
- fileName);
- }
-}
diff --git a/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/ThirdPartyVerificationTest.java b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/ThirdPartyVerificationTest.java
deleted file mode 100644
index ec86d0f..0000000
--- a/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/ThirdPartyVerificationTest.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.asllib.marshallable;
-
-import com.android.asllib.testutils.TestUtils;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public class ThirdPartyVerificationTest {
- private static final String THIRD_PARTY_VERIFICATION_HR_PATH =
- "com/android/asllib/thirdpartyverification/hr";
- private static final String THIRD_PARTY_VERIFICATION_OD_PATH =
- "com/android/asllib/thirdpartyverification/od";
-
- private static final String VALID_FILE_NAME = "valid.xml";
- private static final String MISSING_URL_FILE_NAME = "missing-url.xml";
-
- /** Logic for setting up tests (empty if not yet needed). */
- public static void main(String[] params) throws Exception {}
-
- @Before
- public void setUp() throws Exception {
- System.out.println("set up.");
- }
-
- /** Test for valid. */
- @Test
- public void testValid() throws Exception {
- System.out.println("starting testValid.");
- testHrToOdThirdPartyVerification(VALID_FILE_NAME);
- testOdToHrThirdPartyVerification(VALID_FILE_NAME);
- }
-
- /** Tests missing url. */
- @Test
- public void testMissingUrl() throws Exception {
- System.out.println("starting testMissingUrl.");
- hrToOdExpectException(MISSING_URL_FILE_NAME);
- odToHrExpectException(MISSING_URL_FILE_NAME);
- }
-
- private void hrToOdExpectException(String fileName) {
- TestUtils.hrToOdExpectException(
- new ThirdPartyVerificationFactory(), THIRD_PARTY_VERIFICATION_HR_PATH, fileName);
- }
-
- private void odToHrExpectException(String fileName) {
- TestUtils.odToHrExpectException(
- new ThirdPartyVerificationFactory(), THIRD_PARTY_VERIFICATION_OD_PATH, fileName);
- }
-
- private void testHrToOdThirdPartyVerification(String fileName) throws Exception {
- TestUtils.testHrToOd(
- TestUtils.document(),
- new ThirdPartyVerificationFactory(),
- THIRD_PARTY_VERIFICATION_HR_PATH,
- THIRD_PARTY_VERIFICATION_OD_PATH,
- fileName);
- }
-
- private void testOdToHrThirdPartyVerification(String fileName) throws Exception {
- TestUtils.testOdToHr(
- TestUtils.document(),
- new ThirdPartyVerificationFactory(),
- THIRD_PARTY_VERIFICATION_OD_PATH,
- THIRD_PARTY_VERIFICATION_HR_PATH,
- fileName);
- }
-}
diff --git a/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/TransparencyInfoTest.java b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/TransparencyInfoTest.java
index f494240..8a0b35e 100644
--- a/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/TransparencyInfoTest.java
+++ b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/TransparencyInfoTest.java
@@ -29,9 +29,6 @@
"com/android/asllib/transparencyinfo/hr";
private static final String TRANSPARENCY_INFO_OD_PATH =
"com/android/asllib/transparencyinfo/od";
-
- private static final String VALID_EMPTY_FILE_NAME = "valid-empty.xml";
- private static final String WITH_DEVELOPER_INFO_FILE_NAME = "with-developer-info.xml";
private static final String WITH_APP_INFO_FILE_NAME = "with-app-info.xml";
@Before
@@ -39,22 +36,6 @@
System.out.println("set up.");
}
- /** Test for transparency info valid empty. */
- @Test
- public void testTransparencyInfoValidEmptyFile() throws Exception {
- System.out.println("starting testTransparencyInfoValidEmptyFile.");
- testHrToOdTransparencyInfo(VALID_EMPTY_FILE_NAME);
- testOdToHrTransparencyInfo(VALID_EMPTY_FILE_NAME);
- }
-
- /** Test for transparency info with developer info. */
- @Test
- public void testTransparencyInfoWithDeveloperInfo() throws Exception {
- System.out.println("starting testTransparencyInfoWithDeveloperInfo.");
- testHrToOdTransparencyInfo(WITH_DEVELOPER_INFO_FILE_NAME);
- testOdToHrTransparencyInfo(WITH_DEVELOPER_INFO_FILE_NAME);
- }
-
/** Test for transparency info with app info. */
@Test
public void testTransparencyInfoWithAppInfo() throws Exception {
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/hr/with-safety-labels.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/hr/with-safety-labels.xml
index 53794a1..03e71d2 100644
--- a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/hr/with-safety-labels.xml
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/hr/with-safety-labels.xml
@@ -1,4 +1,4 @@
<app-metadata-bundles version="123456">
- <safety-labels version="12345">
+ <safety-labels>
</safety-labels>
</app-metadata-bundles>
\ No newline at end of file
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/hr/with-transparency-info.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/hr/with-transparency-info.xml
index 00bcfa8..a00ef65 100644
--- a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/hr/with-transparency-info.xml
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/hr/with-transparency-info.xml
@@ -1,4 +1,15 @@
<app-metadata-bundles version="123456">
-<transparency-info>
-</transparency-info>
+ <transparency-info>
+ <app-info
+ apsCompliant="false"
+ privacyPolicy="www.example.com">
+ <first-party-endpoints>
+ <item>url1</item>
+ </first-party-endpoints>
+ <service-provider-endpoints>
+ <item>url55</item>
+ <item>url56</item>
+ </service-provider-endpoints>
+ </app-info>
+ </transparency-info>
</app-metadata-bundles>
\ No newline at end of file
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/od/with-safety-labels.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/od/with-safety-labels.xml
index 74644ed..f00fb26 100644
--- a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/od/with-safety-labels.xml
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/od/with-safety-labels.xml
@@ -1,6 +1,5 @@
<bundle>
<long name="version" value="123456"/>
<pbundle_as_map name="safety_labels">
- <long name="version" value="12345"/>
</pbundle_as_map>
</bundle>
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/od/with-transparency-info.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/od/with-transparency-info.xml
index 63c5094..d0c8668 100644
--- a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/od/with-transparency-info.xml
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/od/with-transparency-info.xml
@@ -1,4 +1,16 @@
<bundle>
<long name="version" value="123456"/>
- <pbundle_as_map name="transparency_info"/>
+ <pbundle_as_map name="transparency_info">
+ <pbundle_as_map name="app_info">
+ <boolean name="aps_compliant" value="false"/>
+ <string name="privacy_policy" value="www.example.com"/>
+ <string-array name="first_party_endpoints" num="1">
+ <item value="url1"/>
+ </string-array>
+ <string-array name="service_provider_endpoints" num="2">
+ <item value="url55"/>
+ <item value="url56"/>
+ </string-array>
+ </pbundle_as_map>
+ </pbundle_as_map>
</bundle>
\ No newline at end of file
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/appinfo/hr/all-fields-valid.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/appinfo/hr/all-fields-valid.xml
index 883170a2..0d15efc 100644
--- a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/appinfo/hr/all-fields-valid.xml
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/appinfo/hr/all-fields-valid.xml
@@ -1,14 +1,11 @@
<app-info
- title="beervision"
- description="a beer app"
- containsAds="true"
- obeyAps="false"
- adsFingerprinting="false"
- securityFingerprinting="false"
- privacyPolicy="www.example.com"
- securityEndpoints="url1|url2|url3"
- firstPartyEndpoints="url1"
- serviceProviderEndpoints="url55|url56"
- category="Food and drink"
- email="max@maxloh.com"
- website="www.example.com" />
\ No newline at end of file
+ apsCompliant="false"
+ privacyPolicy="www.example.com">
+ <first-party-endpoints>
+ <item>url1</item>
+ </first-party-endpoints>
+ <service-provider-endpoints>
+ <item>url55</item>
+ <item>url56</item>
+ </service-provider-endpoints>
+</app-info>
\ No newline at end of file
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/appinfo/od/all-fields-valid.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/appinfo/od/all-fields-valid.xml
index 6e976a3..bce5179 100644
--- a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/appinfo/od/all-fields-valid.xml
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/appinfo/od/all-fields-valid.xml
@@ -1,25 +1,12 @@
<pbundle_as_map name="app_info">
- <string name="title" value="beervision"/>
- <string name="description" value="a beer app"/>
- <boolean name="contains_ads" value="true"/>
- <boolean name="obey_aps" value="false"/>
- <boolean name="ads_fingerprinting" value="false"/>
- <boolean name="security_fingerprinting" value="false"/>
+ <boolean name="aps_compliant" value="false"/>
<string name="privacy_policy" value="www.example.com"/>
- <string-array name="security_endpoint" num="3">
- <item value="url1"/>
- <item value="url2"/>
- <item value="url3"/>
- </string-array>
- <string-array name="first_party_endpoint" num="1">
+ <string-array name="first_party_endpoints" num="1">
<item value="url1"/>
</string-array>
- <string-array name="service_provider_endpoint" num="2">
+ <string-array name="service_provider_endpoints" num="2">
<item value="url55"/>
<item value="url56"/>
</string-array>
- <string name="category" value="Food and drink"/>
- <string name="email" value="max@maxloh.com"/>
- <string name="website" value="www.example.com"/>
</pbundle_as_map>
\ No newline at end of file
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/hr/missing-version.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/hr/missing-version.xml
deleted file mode 100644
index 762f3bd..0000000
--- a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/hr/missing-version.xml
+++ /dev/null
@@ -1,2 +0,0 @@
-<safety-labels>
-</safety-labels>
\ No newline at end of file
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/hr/valid-empty.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/hr/valid-empty.xml
index 7decfd4..92d10ca 100644
--- a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/hr/valid-empty.xml
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/hr/valid-empty.xml
@@ -1 +1 @@
-<safety-labels version="12345"></safety-labels>
\ No newline at end of file
+<safety-labels></safety-labels>
\ No newline at end of file
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/hr/with-data-labels.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/hr/with-data-labels.xml
index 84456da..ca3d9f0 100644
--- a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/hr/with-data-labels.xml
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/hr/with-data-labels.xml
@@ -1,4 +1,4 @@
-<safety-labels version="12345">
+<safety-labels>
<data-labels>
<data-shared dataType="location_data_type_approx_location"
isSharingOptional="false"
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/hr/with-security-labels.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/hr/with-security-labels.xml
index 940e48a..c962785 100644
--- a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/hr/with-security-labels.xml
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/hr/with-security-labels.xml
@@ -1,4 +1,4 @@
-<safety-labels version="12345">
+<safety-labels>
<security-labels
isDataDeletable="true"
isDataEncrypted="false"
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/hr/with-third-party-verification.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/hr/with-third-party-verification.xml
index bfbc5ae..0805290 100644
--- a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/hr/with-third-party-verification.xml
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/hr/with-third-party-verification.xml
@@ -1,4 +1,4 @@
-<safety-labels version="12345">
+<safety-labels>
<third-party-verification url="www.example.com">
</third-party-verification>
</safety-labels>
\ No newline at end of file
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/od/missing-version.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/od/missing-version.xml
deleted file mode 100644
index 3fbe359..0000000
--- a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/od/missing-version.xml
+++ /dev/null
@@ -1,2 +0,0 @@
-<pbundle_as_map name="safety_labels">
-</pbundle_as_map>
\ No newline at end of file
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/od/valid-empty.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/od/valid-empty.xml
index 4f03d88..3fbe359 100644
--- a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/od/valid-empty.xml
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/od/valid-empty.xml
@@ -1,3 +1,2 @@
<pbundle_as_map name="safety_labels">
- <long name="version" value="12345"/>
</pbundle_as_map>
\ No newline at end of file
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/od/with-data-labels.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/od/with-data-labels.xml
index fa2a3f8..db92e02 100644
--- a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/od/with-data-labels.xml
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/od/with-data-labels.xml
@@ -1,5 +1,4 @@
<pbundle_as_map name="safety_labels">
- <long name="version" value="12345"/>
<pbundle_as_map name="data_labels">
<pbundle_as_map name="data_shared">
<pbundle_as_map name="location">
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/od/with-security-labels.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/od/with-security-labels.xml
index b39c562b..9246180 100644
--- a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/od/with-security-labels.xml
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/od/with-security-labels.xml
@@ -1,5 +1,4 @@
<pbundle_as_map name="safety_labels">
- <long name="version" value="12345"/>
<pbundle_as_map name="security_labels">
<boolean name="is_data_deletable" value="true" />
<boolean name="is_data_encrypted" value="false" />
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/od/with-third-party-verification.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/od/with-third-party-verification.xml
index 10653ff..fd435c5 100644
--- a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/od/with-third-party-verification.xml
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/od/with-third-party-verification.xml
@@ -1,5 +1,4 @@
<pbundle_as_map name="safety_labels">
- <long name="version" value="12345"/>
<pbundle_as_map name="third_party_verification">
<string name="url" value="www.example.com"/>
</pbundle_as_map>
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/transparencyinfo/hr/with-app-info.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/transparencyinfo/hr/with-app-info.xml
index a7c48fc..2512ca4 100644
--- a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/transparencyinfo/hr/with-app-info.xml
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/transparencyinfo/hr/with-app-info.xml
@@ -1,4 +1,14 @@
<transparency-info>
- <app-info title="beervision" description="a beer app" containsAds="true" obeyAps="false" adsFingerprinting="false" securityFingerprinting="false" privacyPolicy="www.example.com" securityEndpoints="url1|url2|url3" firstPartyEndpoints="url1" serviceProviderEndpoints="url55|url56" category="Food and drink" email="max@maxloh.com" />
+ <app-info
+ apsCompliant="false"
+ privacyPolicy="www.example.com">
+ <first-party-endpoints>
+ <item>url1</item>
+ </first-party-endpoints>
+ <service-provider-endpoints>
+ <item>url55</item>
+ <item>url56</item>
+ </service-provider-endpoints>
+ </app-info>
</transparency-info>
\ No newline at end of file
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/transparencyinfo/od/with-app-info.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/transparencyinfo/od/with-app-info.xml
index b813641..c7bdd97 100644
--- a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/transparencyinfo/od/with-app-info.xml
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/transparencyinfo/od/with-app-info.xml
@@ -1,26 +1,14 @@
<pbundle_as_map name="transparency_info">
<pbundle_as_map name="app_info">
- <string name="title" value="beervision"/>
- <string name="description" value="a beer app"/>
- <boolean name="contains_ads" value="true"/>
- <boolean name="obey_aps" value="false"/>
- <boolean name="ads_fingerprinting" value="false"/>
- <boolean name="security_fingerprinting" value="false"/>
+ <boolean name="aps_compliant" value="false"/>
<string name="privacy_policy" value="www.example.com"/>
- <string-array name="security_endpoint" num="3">
- <item value="url1"/>
- <item value="url2"/>
- <item value="url3"/>
- </string-array>
- <string-array name="first_party_endpoint" num="1">
+ <string-array name="first_party_endpoints" num="1">
<item value="url1"/>
</string-array>
- <string-array name="service_provider_endpoint" num="2">
+ <string-array name="service_provider_endpoints" num="2">
<item value="url55"/>
<item value="url56"/>
</string-array>
- <string name="category" value="Food and drink"/>
- <string name="email" value="max@maxloh.com"/>
</pbundle_as_map>
</pbundle_as_map>
\ No newline at end of file
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/contacts/hr.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/contacts/hr.xml
index b2ff449..cadf213 100644
--- a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/contacts/hr.xml
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/contacts/hr.xml
@@ -1,5 +1,5 @@
<app-metadata-bundles version="123">
- <safety-labels version="12345">
+ <safety-labels>
<data-labels>
<data-shared dataCategory="contacts"
dataType="contacts"
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/contacts/od.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/contacts/od.xml
index 81277bf..7aafd23 100644
--- a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/contacts/od.xml
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/contacts/od.xml
@@ -1,7 +1,6 @@
<bundle>
<long name="version" value="123"/>
<pbundle_as_map name="safety_labels">
- <long name="version" value="12345"/>
<pbundle_as_map name="data_labels">
<pbundle_as_map name="data_shared">
<pbundle_as_map name="contacts">
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/general/hr.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/general/hr.xml
index 41b32b5..5923079 100644
--- a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/general/hr.xml
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/general/hr.xml
@@ -1,5 +1,5 @@
<app-metadata-bundles version="123">
- <safety-labels version="12345">
+ <safety-labels>
<data-labels>
<data-shared
dataType="location_data_type_approx_location"
@@ -10,24 +10,18 @@
isSharingOptional="true"
purposes="app_functionality|analytics" />
</data-labels>
- <security-labels
- isDataDeletable="true"
- isDataEncrypted="false"
- />
- <third-party-verification url="www.example.com">
- </third-party-verification>
</safety-labels>
<system-app-safety-label declaration="true">
</system-app-safety-label>
<transparency-info>
- <developer-info
- name="max"
- email="max@example.com"
- address="111 blah lane"
- countryRegion="US"
- relationship="aosp"
- website="example.com"
- registryId="registry_id" />
- <app-info title="beervision" description="a beer app" containsAds="true" obeyAps="false" adsFingerprinting="false" securityFingerprinting="false" privacyPolicy="www.example.com" securityEndpoints="url1|url2|url3" firstPartyEndpoints="url1" serviceProviderEndpoints="url55|url56" category="Food and drink" email="max@maxloh.com" />
+ <app-info apsCompliant="false" privacyPolicy="www.example.com">
+ <first-party-endpoints>
+ <item>url1</item>
+ </first-party-endpoints>
+ <service-provider-endpoints>
+ <item>url55</item>
+ <item>url56</item>
+ </service-provider-endpoints>
+ </app-info>
</transparency-info>
</app-metadata-bundles>
\ No newline at end of file
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/general/od.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/general/od.xml
index c11ac43..c24087e 100644
--- a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/general/od.xml
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/general/od.xml
@@ -1,7 +1,6 @@
<bundle>
<long name="version" value="123"/>
<pbundle_as_map name="safety_labels">
- <long name="version" value="12345"/>
<pbundle_as_map name="data_labels">
<pbundle_as_map name="data_shared">
<pbundle_as_map name="location">
@@ -21,49 +20,21 @@
</pbundle_as_map>
</pbundle_as_map>
</pbundle_as_map>
- <pbundle_as_map name="security_labels">
- <boolean name="is_data_deletable" value="true"/>
- <boolean name="is_data_encrypted" value="false"/>
- </pbundle_as_map>
- <pbundle_as_map name="third_party_verification">
- <string name="url" value="www.example.com"/>
- </pbundle_as_map>
</pbundle_as_map>
<pbundle_as_map name="system_app_safety_label">
<boolean name="declaration" value="true"/>
</pbundle_as_map>
<pbundle_as_map name="transparency_info">
- <pbundle_as_map name="developer_info">
- <string name="name" value="max"/>
- <string name="email" value="max@example.com"/>
- <string name="address" value="111 blah lane"/>
- <string name="country_region" value="US"/>
- <long name="relationship" value="5"/>
- <string name="website" value="example.com"/>
- <string name="app_developer_registry_id" value="registry_id"/>
- </pbundle_as_map>
<pbundle_as_map name="app_info">
- <string name="title" value="beervision"/>
- <string name="description" value="a beer app"/>
- <boolean name="contains_ads" value="true"/>
- <boolean name="obey_aps" value="false"/>
- <boolean name="ads_fingerprinting" value="false"/>
- <boolean name="security_fingerprinting" value="false"/>
+ <boolean name="aps_compliant" value="false"/>
<string name="privacy_policy" value="www.example.com"/>
- <string-array name="security_endpoint" num="3">
- <item value="url1"/>
- <item value="url2"/>
- <item value="url3"/>
- </string-array>
- <string-array name="first_party_endpoint" num="1">
+ <string-array name="first_party_endpoints" num="1">
<item value="url1"/>
</string-array>
- <string-array name="service_provider_endpoint" num="2">
+ <string-array name="service_provider_endpoints" num="2">
<item value="url55"/>
<item value="url56"/>
</string-array>
- <string name="category" value="Food and drink"/>
- <string name="email" value="max@maxloh.com"/>
</pbundle_as_map>
</pbundle_as_map>
</bundle>
\ No newline at end of file
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/location/hr.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/location/hr.xml
index ac844b3..a4242d0 100644
--- a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/location/hr.xml
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/location/hr.xml
@@ -1,5 +1,5 @@
<app-metadata-bundles version="123">
- <safety-labels version="12345">
+ <safety-labels>
<data-labels>
<data-shared dataCategory="location"
dataType="precise_location"
diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/location/od.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/location/od.xml
index d0a3bfa..79afaf7 100644
--- a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/location/od.xml
+++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/location/od.xml
@@ -1,7 +1,6 @@
<bundle>
<long name="version" value="123"/>
<pbundle_as_map name="safety_labels">
- <long name="version" value="12345"/>
<pbundle_as_map name="data_labels">
<pbundle_as_map name="data_shared">
<pbundle_as_map name="location">
diff --git a/tools/lint/framework/checks/src/main/java/com/google/android/lint/AndroidFrameworkIssueRegistry.kt b/tools/lint/framework/checks/src/main/java/com/google/android/lint/AndroidFrameworkIssueRegistry.kt
index 624a198..5c64697 100644
--- a/tools/lint/framework/checks/src/main/java/com/google/android/lint/AndroidFrameworkIssueRegistry.kt
+++ b/tools/lint/framework/checks/src/main/java/com/google/android/lint/AndroidFrameworkIssueRegistry.kt
@@ -41,6 +41,7 @@
PermissionAnnotationDetector.ISSUE_MISSING_PERMISSION_ANNOTATION,
PermissionMethodDetector.ISSUE_PERMISSION_METHOD_USAGE,
PermissionMethodDetector.ISSUE_CAN_BE_PERMISSION_METHOD,
+ FeatureAutomotiveDetector.ISSUE,
)
override val api: Int
diff --git a/tools/lint/framework/checks/src/main/java/com/google/android/lint/FeatureAutomotiveDetector.kt b/tools/lint/framework/checks/src/main/java/com/google/android/lint/FeatureAutomotiveDetector.kt
new file mode 100644
index 0000000..972b0c9
--- /dev/null
+++ b/tools/lint/framework/checks/src/main/java/com/google/android/lint/FeatureAutomotiveDetector.kt
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.android.lint
+
+import com.android.tools.lint.detector.api.Category
+import com.android.tools.lint.detector.api.ConstantEvaluator
+import com.android.tools.lint.detector.api.Detector
+import com.android.tools.lint.detector.api.Implementation
+import com.android.tools.lint.detector.api.Issue
+import com.android.tools.lint.detector.api.JavaContext
+import com.android.tools.lint.detector.api.Scope
+import com.android.tools.lint.detector.api.Severity
+import com.android.tools.lint.detector.api.SourceCodeScanner
+import com.intellij.psi.PsiMethod
+import java.util.EnumSet
+import org.jetbrains.uast.UCallExpression
+import org.jetbrains.uast.ULiteralExpression
+import org.jetbrains.uast.UReferenceExpression
+
+/**
+ * A detector to check the usage of PackageManager.hasSystemFeature("
+ * android.hardware.type.automotive") in CTS tests.
+ */
+class FeatureAutomotiveDetector : Detector(), SourceCodeScanner {
+
+ companion object {
+
+ val EXPLANATION =
+ """
+ This class uses PackageManager.hasSystemFeature(\"android.hardware.type.automotive\") \
+ or other equivalent methods. \
+ If it is used to make a CTS test behave differently on AAOS, you should use \
+ @RequireAutomotive or @RequireNotAutomotive instead; otherwise, please ignore this \
+ warning. See https://g3doc.corp.google.com/wireless/android/partner/compatibility/\
+ g3doc/dev/write-a-test/index.md#write-a-test-that-behaves-differently-on-aaos
+ """
+
+ val ISSUE: Issue =
+ Issue.create(
+ id = "UsingFeatureAutomotiveInCTS",
+ briefDescription =
+ "PackageManager.hasSystemFeature(\"" +
+ " android.hardware.type.automotive\") is used in CTS tests",
+ explanation = EXPLANATION,
+ category = Category.TESTING,
+ priority = 8,
+ severity = Severity.WARNING,
+ implementation =
+ Implementation(
+ FeatureAutomotiveDetector::class.java,
+ EnumSet.of(Scope.JAVA_FILE, Scope.TEST_SOURCES)
+ )
+ )
+ }
+
+ override fun getApplicableMethodNames() =
+ listOf("hasSystemFeature", "hasFeature", "hasDeviceFeature", "bypassTestForFeatures")
+
+ override fun visitMethodCall(context: JavaContext, node: UCallExpression, method: PsiMethod) {
+ node.valueArguments.forEach {
+ val value =
+ when (it) {
+ is ULiteralExpression -> it.value
+ is UReferenceExpression -> ConstantEvaluator.evaluate(context, it)
+ else -> null
+ }
+ if (value is String && value == "android.hardware.type.automotive") {
+ context.report(
+ issue = ISSUE,
+ location = context.getNameLocation(method),
+ message = EXPLANATION
+ )
+ }
+ }
+ }
+}
diff --git a/tools/lint/framework/checks/src/test/java/com/google/android/lint/FeatureAutomotiveDetectorTest.kt b/tools/lint/framework/checks/src/test/java/com/google/android/lint/FeatureAutomotiveDetectorTest.kt
new file mode 100644
index 0000000..b5e2c00
--- /dev/null
+++ b/tools/lint/framework/checks/src/test/java/com/google/android/lint/FeatureAutomotiveDetectorTest.kt
@@ -0,0 +1,366 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.android.lint
+
+import com.android.tools.lint.checks.infrastructure.LintDetectorTest
+import com.android.tools.lint.checks.infrastructure.TestFile
+import com.android.tools.lint.checks.infrastructure.TestLintTask
+import com.android.tools.lint.detector.api.Detector
+import com.android.tools.lint.detector.api.Issue
+import org.junit.Test
+
+@Suppress("UnstableApiUsage")
+class FeatureAutomotiveDetectorTest : LintDetectorTest() {
+ val explanation =
+ FeatureAutomotiveDetector.EXPLANATION.replace("\\", "").replace("\n ", "") +
+ " [UsingFeatureAutomotiveInCTS]"
+
+ override fun getDetector(): Detector = FeatureAutomotiveDetector()
+ override fun getIssues(): List<Issue> = listOf(FeatureAutomotiveDetector.ISSUE)
+ override fun lint(): TestLintTask = super.lint().allowMissingSdk(true)
+
+ @Test
+ fun testWarning1() {
+ lint()
+ .files(
+ java(
+ """
+ import android.content.pm.PackageManager;
+
+ public class Foo {
+
+ private void fun() {
+ PackageManager.getInstance().hasSystemFeature(
+ "android.hardware.type.automotive");
+ }
+ }
+ """
+ )
+ .indented(),
+ *stubs
+ )
+ .issues(FeatureAutomotiveDetector.ISSUE)
+ .run()
+ .expect(
+ """
+ src/android/content/pm/PackageManager.java:13: Warning: $explanation
+ public boolean hasSystemFeature(String feature) {
+ ~~~~~~~~~~~~~~~~
+ 0 errors, 1 warnings
+ """
+ )
+ }
+
+ @Test
+ fun testWarning2() {
+ lint()
+ .files(
+ java(
+ """
+ import android.content.pm.PackageManager;
+
+ public class Foo {
+
+ private void fun() {
+ String featureName = "android.hardware.type.automotive";
+ PackageManager.getInstance().hasSystemFeature(featureName);
+ }
+ }
+ """
+ )
+ .indented(),
+ *stubs
+ )
+ .issues(FeatureAutomotiveDetector.ISSUE)
+ .run()
+ .expect(
+ """
+ src/android/content/pm/PackageManager.java:13: Warning: $explanation
+ public boolean hasSystemFeature(String feature) {
+ ~~~~~~~~~~~~~~~~
+ 0 errors, 1 warnings
+ """
+ )
+ }
+
+ @Test
+ fun testWarning3() {
+ lint()
+ .files(
+ java(
+ """
+ import android.content.pm.PackageManager;
+
+ public class Foo {
+
+ private void fun() {
+ PackageManager.getInstance().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
+ }
+ }
+ """
+ )
+ .indented(),
+ *stubs
+ )
+ .issues(FeatureAutomotiveDetector.ISSUE)
+ .run()
+ .expect(
+ """
+ src/android/content/pm/PackageManager.java:13: Warning: $explanation
+ public boolean hasSystemFeature(String feature) {
+ ~~~~~~~~~~~~~~~~
+ 0 errors, 1 warnings
+ """
+ )
+ }
+
+ @Test
+ fun testWarning4() {
+ lint()
+ .files(
+ java(
+ """
+ import android.content.pm.PackageManager;
+
+ public class Foo {
+
+ private void fun() {
+ String featureName = PackageManager.FEATURE_AUTOMOTIVE;
+ PackageManager.getInstance().hasSystemFeature(featureName);
+ }
+ }
+ """
+ )
+ .indented(),
+ *stubs
+ )
+ .issues(FeatureAutomotiveDetector.ISSUE)
+ .run()
+ .expect(
+ """
+ src/android/content/pm/PackageManager.java:13: Warning: $explanation
+ public boolean hasSystemFeature(String feature) {
+ ~~~~~~~~~~~~~~~~
+ 0 errors, 1 warnings
+ """
+ )
+ }
+
+ @Test
+ fun testWarning5() {
+ lint()
+ .files(
+ java(
+ """
+ import com.android.example.Utils;
+
+ public class Foo {
+
+ private void fun() {
+ Utils.hasFeature("android.hardware.type.automotive");
+ }
+ }
+ """
+ )
+ .indented(),
+ *stubs
+ )
+ .issues(FeatureAutomotiveDetector.ISSUE)
+ .run()
+ .expect(
+ """
+ src/com/android/example/Utils.java:7: Warning: $explanation
+ public static boolean hasFeature(String feature) {
+ ~~~~~~~~~~
+ 0 errors, 1 warnings
+ """
+ )
+ }
+
+ @Test
+ fun testWarning6() {
+ lint()
+ .files(
+ java(
+ """
+ import com.android.example.Utils;
+
+ public class Foo {
+
+ private void fun() {
+ Utils.hasDeviceFeature("android.hardware.type.automotive");
+ }
+ }
+ """
+ )
+ .indented(),
+ *stubs
+ )
+ .issues(FeatureAutomotiveDetector.ISSUE)
+ .run()
+ .expect(
+ """
+ src/com/android/example/Utils.java:11: Warning: $explanation
+ public static boolean hasDeviceFeature(String feature) {
+ ~~~~~~~~~~~~~~~~
+ 0 errors, 1 warnings
+ """
+ )
+ }
+
+ @Test
+ fun testWarning7() {
+ lint()
+ .files(
+ java(
+ """
+ import com.android.example.Utils;
+
+ public class Foo {
+
+ private void fun() {
+ Utils.hasFeature(new Object(), "android.hardware.type.automotive");
+ }
+ }
+ """
+ )
+ .indented(),
+ *stubs
+ )
+ .issues(FeatureAutomotiveDetector.ISSUE)
+ .run()
+ .expect(
+ """
+ src/com/android/example/Utils.java:15: Warning: $explanation
+ public static boolean hasFeature(Object object, String feature) {
+ ~~~~~~~~~~
+ 0 errors, 1 warnings
+ """
+ )
+ }
+
+ @Test
+ fun testWarning8() {
+ lint()
+ .files(
+ java(
+ """
+ import com.android.example.Utils;
+
+ public class Foo {
+
+ private void fun() {
+ Utils.bypassTestForFeatures("android.hardware.type.automotive");
+ }
+ }
+ """
+ )
+ .indented(),
+ *stubs
+ )
+ .issues(FeatureAutomotiveDetector.ISSUE)
+ .run()
+ .expect(
+ """
+ src/com/android/example/Utils.java:19: Warning: $explanation
+ public static boolean bypassTestForFeatures(String feature) {
+ ~~~~~~~~~~~~~~~~~~~~~
+ 0 errors, 1 warnings
+ """
+ )
+ }
+
+ @Test
+ fun testNoWarning() {
+ lint()
+ .files(
+ java(
+ """
+ import android.content.pm.PackageManager;
+
+ public class Foo {
+ private void fun() {
+ String featureName1 = "android.hardware.type.automotive";
+ String featureName2 = PackageManager.FEATURE_AUTOMOTIVE;
+ String notFeatureName = "FEATURE_AUTOMOTIVE";
+ PackageManager.getInstance().hasSystemFeature(notFeatureName);
+ /*
+ PackageManager.getInstance().hasSystemFeature(
+ "android.hardware.type.automotive");
+ */
+ }
+ }
+ """
+ )
+ .indented(),
+ *stubs
+ )
+ .issues(FeatureAutomotiveDetector.ISSUE)
+ .run()
+ .expectClean()
+ }
+
+ private val pmStub: TestFile =
+ java(
+ """
+ package android.content.pm;
+
+ import java.lang.String;
+
+ public class PackageManager {
+ public static final String FEATURE_AUTOMOTIVE = "android.hardware.type.automotive";
+
+ public static PackageManager getInstance() {
+ return new PackageManager();
+ }
+
+ public boolean hasSystemFeature(String feature) {
+ return true;
+ }
+ }
+ """
+ )
+
+ private val exampleStub: TestFile =
+ java(
+ """
+ package com.android.example;
+
+ import java.lang.String;
+
+ public class Utils {
+ public static boolean hasFeature(String feature) {
+ return true;
+ }
+
+ public static boolean hasDeviceFeature(String feature) {
+ return true;
+ }
+
+ public static boolean hasFeature(Object object, String feature) {
+ return true;
+ }
+
+ public static boolean bypassTestForFeatures(String feature) {
+ return true;
+ }
+ }
+ """
+ )
+
+ private val stubs = arrayOf(pmStub, exampleStub)
+}