Merge "Fix NPE in RemoteInput.getResultsFromIntent" into main
diff --git a/AconfigFlags.bp b/AconfigFlags.bp
index b54022b..16389b3 100644
--- a/AconfigFlags.bp
+++ b/AconfigFlags.bp
@@ -265,6 +265,23 @@
}
// VirtualDeviceManager
+cc_aconfig_library {
+ name: "android.companion.virtualdevice.flags-aconfig-cc",
+ aconfig_declarations: "android.companion.virtualdevice.flags-aconfig",
+}
+
+java_aconfig_library {
+ name: "android.companion.virtualdevice.flags-aconfig-java",
+ aconfig_declarations: "android.companion.virtualdevice.flags-aconfig",
+ defaults: ["framework-minus-apex-aconfig-java-defaults"],
+}
+
+aconfig_declarations {
+ name: "android.companion.virtualdevice.flags-aconfig",
+ package: "android.companion.virtualdevice.flags",
+ srcs: ["core/java/android/companion/virtual/flags/*.aconfig"],
+}
+
java_aconfig_library {
name: "android.companion.virtual.flags-aconfig-java",
aconfig_declarations: "android.companion.virtual.flags-aconfig",
diff --git a/Ravenwood.bp b/Ravenwood.bp
index 03a23ba..ca73378 100644
--- a/Ravenwood.bp
+++ b/Ravenwood.bp
@@ -32,7 +32,6 @@
cmd: "$(location hoststubgen) " +
"@$(location ravenwood/ravenwood-standard-options.txt) " +
- "--out-stub-jar $(location ravenwood_stub.jar) " +
"--out-impl-jar $(location ravenwood.jar) " +
"--gen-keep-all-file $(location hoststubgen_keep_all.txt) " +
@@ -49,7 +48,6 @@
],
out: [
"ravenwood.jar",
- "ravenwood_stub.jar", // It's not used. TODO: Update hoststubgen to make it optional.
// Following files are created just as FYI.
"hoststubgen_keep_all.txt",
diff --git a/cmds/gpu_counter_producer/Android.bp b/cmds/gpu_counter_producer/Android.bp
index 2232345..d645d06 100644
--- a/cmds/gpu_counter_producer/Android.bp
+++ b/cmds/gpu_counter_producer/Android.bp
@@ -19,6 +19,4 @@
"-Wunused",
"-Wunreachable-code",
],
-
- soc_specific: true,
}
diff --git a/cmds/uinput/Android.bp b/cmds/uinput/Android.bp
index 4b08d96..da497dc 100644
--- a/cmds/uinput/Android.bp
+++ b/cmds/uinput/Android.bp
@@ -22,7 +22,7 @@
name: "uinput",
wrapper: "uinput.sh",
srcs: [
- "**/*.java",
+ "src/**/*.java",
":uinputcommand_aidl",
],
required: ["libuinputcommand_jni"],
diff --git a/cmds/uinput/TEST_MAPPING b/cmds/uinput/TEST_MAPPING
new file mode 100644
index 0000000..e7d619c
--- /dev/null
+++ b/cmds/uinput/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+ "imports": [
+ {
+ "path": "frameworks/native/services/inputflinger"
+ }
+ ],
+ "postsubmit": [
+ {
+ "name": "UinputTests"
+ }
+ ]
+}
diff --git a/cmds/uinput/src/com/android/commands/uinput/EvemuParser.java b/cmds/uinput/src/com/android/commands/uinput/EvemuParser.java
new file mode 100644
index 0000000..b89e2cd
--- /dev/null
+++ b/cmds/uinput/src/com/android/commands/uinput/EvemuParser.java
@@ -0,0 +1,380 @@
+/*
+ * Copyright 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.commands.uinput;
+
+import android.annotation.Nullable;
+import android.util.SparseArray;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.Reader;
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Queue;
+
+import src.com.android.commands.uinput.InputAbsInfo;
+
+/**
+ * Parser for the <a href="https://gitlab.freedesktop.org/libevdev/evemu">FreeDesktop evemu</a>
+ * event recording format.
+ */
+public class EvemuParser implements EventParser {
+ private static final String TAG = "UinputEvemuParser";
+
+ /**
+ * The device ID to use for all events. Since evemu files only support single-device
+ * recordings, this will always be the same.
+ */
+ private static final int DEVICE_ID = 1;
+ private static final int REGISTRATION_DELAY_MILLIS = 500;
+
+ private static class CommentAwareReader {
+ private final BufferedReader mReader;
+ private String mNextLine;
+
+ CommentAwareReader(BufferedReader in) throws IOException {
+ mReader = in;
+ mNextLine = findNextLine();
+ }
+
+ private @Nullable String findNextLine() throws IOException {
+ String line = "";
+ while (line != null && line.length() == 0) {
+ String unstrippedLine = mReader.readLine();
+ if (unstrippedLine == null) {
+ // End of file.
+ return null;
+ }
+ line = stripComments(unstrippedLine);
+ }
+ return line;
+ }
+
+ private static String stripComments(String line) {
+ int index = line.indexOf('#');
+ // 'N:' lines (which contain the name of the input device) do not support trailing
+ // comments, to support recording device names that contain #s.
+ if (index < 0 || line.startsWith("N: ")) {
+ return line;
+ } else {
+ return line.substring(0, index).strip();
+ }
+ }
+
+ /**
+ * Returns the next line of the file that isn't blank when stripped of comments, or
+ * {@code null} if the end of the file is reached. However, it does not advance to the
+ * next line of the file.
+ */
+ public @Nullable String peekLine() {
+ return mNextLine;
+ }
+
+ /** Moves to the next line of the file. */
+ public void advance() throws IOException {
+ mNextLine = findNextLine();
+ }
+
+ public boolean isAtEndOfFile() {
+ return mNextLine == null;
+ }
+ }
+
+ private final CommentAwareReader mReader;
+ /**
+ * The timestamp of the last event returned, of the head of {@link #mQueuedEvents} if there is
+ * one, or -1 if no events have been returned yet.
+ */
+ private long mLastEventTimeMicros = -1;
+ private final Queue<Event> mQueuedEvents = new ArrayDeque<>(2);
+
+ public EvemuParser(Reader in) throws IOException {
+ mReader = new CommentAwareReader(new BufferedReader(in));
+ mQueuedEvents.add(parseRegistrationEvent());
+
+ // The kernel takes a little time to set up an evdev device after the initial
+ // registration. Any events that we try to inject during this period would be silently
+ // dropped, so we delay for a short period after registration and before injecting any
+ // events.
+ final Event.Builder delayEb = new Event.Builder();
+ delayEb.setId(DEVICE_ID);
+ delayEb.setCommand(Event.Command.DELAY);
+ delayEb.setDurationMillis(REGISTRATION_DELAY_MILLIS);
+ mQueuedEvents.add(delayEb.build());
+ }
+
+ /**
+ * Returns the next event in the evemu recording.
+ */
+ public Event getNextEvent() throws IOException {
+ if (!mQueuedEvents.isEmpty()) {
+ return mQueuedEvents.remove();
+ }
+
+ if (mReader.isAtEndOfFile()) {
+ return null;
+ }
+
+ final String[] parts = expectLineWithParts("E", 4);
+ final String[] timeParts = parts[0].split("\\.");
+ if (timeParts.length != 2) {
+ throw new RuntimeException("Invalid timestamp (does not contain a '.')");
+ }
+ // TODO(b/310958309): use timeMicros to set the timestamp on the event being sent.
+ final long timeMicros =
+ Long.parseLong(timeParts[0]) * 1_000_000 + Integer.parseInt(timeParts[1]);
+ final Event.Builder eb = new Event.Builder();
+ eb.setId(DEVICE_ID);
+ eb.setCommand(Event.Command.INJECT);
+ final int eventType = Integer.parseInt(parts[1], 16);
+ final int eventCode = Integer.parseInt(parts[2], 16);
+ final int value = Integer.parseInt(parts[3]);
+ eb.setInjections(new int[] {eventType, eventCode, value});
+
+ if (mLastEventTimeMicros == -1) {
+ // This is the first event being injected, so send it straight away.
+ mLastEventTimeMicros = timeMicros;
+ return eb.build();
+ } else {
+ final long delayMicros = timeMicros - mLastEventTimeMicros;
+ // The shortest delay supported by Handler.sendMessageAtTime (used for timings by the
+ // Device class) is 1ms, so ignore time differences smaller than that.
+ if (delayMicros < 1000) {
+ mLastEventTimeMicros = timeMicros;
+ return eb.build();
+ } else {
+ // Send a delay now, and queue the actual event for the next call.
+ mQueuedEvents.add(eb.build());
+ mLastEventTimeMicros = timeMicros;
+ final Event.Builder delayEb = new Event.Builder();
+ delayEb.setId(DEVICE_ID);
+ delayEb.setCommand(Event.Command.DELAY);
+ delayEb.setDurationMillis((int) (delayMicros / 1000));
+ return delayEb.build();
+ }
+ }
+ }
+
+ private Event parseRegistrationEvent() throws IOException {
+ // The registration details at the start of a recording are specified by a set of lines
+ // that have to be in this order: N, I, P, B, A, L, S. Recordings must have exactly one N
+ // (name) and I (IDs) line. The remaining lines are optional, and there may be multiple
+ // of those lines.
+
+ final Event.Builder eb = new Event.Builder();
+ eb.setId(DEVICE_ID);
+ eb.setCommand(Event.Command.REGISTER);
+ eb.setName(expectLine("N"));
+
+ final String[] idStrings = expectLineWithParts("I", 4);
+ eb.setBusId(Integer.parseInt(idStrings[0], 16));
+ eb.setVid(Integer.parseInt(idStrings[1], 16));
+ eb.setPid(Integer.parseInt(idStrings[2], 16));
+ // TODO(b/302297266): support setting the version ID, and set it to idStrings[3].
+
+ final SparseArray<int[]> config = new SparseArray<>();
+ config.append(Event.UinputControlCode.UI_SET_PROPBIT.getValue(), parseProperties());
+
+ parseAxisBitmaps(config);
+
+ eb.setConfiguration(config);
+ if (config.contains(Event.UinputControlCode.UI_SET_FFBIT.getValue())) {
+ // If the device specifies any force feedback effects, the kernel will require the
+ // ff_effects_max value to be set.
+ eb.setFfEffectsMax(config.get(Event.UinputControlCode.UI_SET_FFBIT.getValue()).length);
+ }
+
+ eb.setAbsInfo(parseAbsInfos());
+
+ // L: and S: lines allow the initial states of the device's LEDs and switches to be
+ // recorded. However, the FreeDesktop implementation doesn't support actually setting these
+ // states at the start of playback (apparently due to concerns over race conditions), and we
+ // have no need for this feature either, so for now just skip over them.
+ skipUnsupportedLines("L");
+ skipUnsupportedLines("S");
+
+ return eb.build();
+ }
+
+ private int[] parseProperties() throws IOException {
+ final List<String> propBitmapParts = new ArrayList<>();
+ String line = acceptLine("P");
+ while (line != null) {
+ propBitmapParts.addAll(List.of(line.strip().split(" ")));
+ line = acceptLine("P");
+ }
+ return hexStringBitmapToEventCodes(propBitmapParts);
+ }
+
+ private void parseAxisBitmaps(SparseArray<int[]> config) throws IOException {
+ final Map<Integer, List<String>> axisBitmapParts = new HashMap<>();
+ String line = acceptLine("B");
+ while (line != null) {
+ final String[] parts = line.strip().split(" ");
+ if (parts.length < 2) {
+ throw new RuntimeException(
+ "Expected event type and at least one bitmap byte on 'B:' line; only found "
+ + parts.length + " elements");
+ }
+ final int eventType = Integer.parseInt(parts[0], 16);
+ // EV_SYN cannot be configured through uinput, so skip it.
+ if (eventType != Event.EV_SYN) {
+ if (!axisBitmapParts.containsKey(eventType)) {
+ axisBitmapParts.put(eventType, new ArrayList<>());
+ }
+ for (int i = 1; i < parts.length; i++) {
+ axisBitmapParts.get(eventType).add(parts[i]);
+ }
+ }
+ line = acceptLine("B");
+ }
+ final List<Integer> eventTypesToSet = new ArrayList<>();
+ for (var entry : axisBitmapParts.entrySet()) {
+ if (entry.getValue().size() == 0) {
+ continue;
+ }
+ final Event.UinputControlCode controlCode =
+ Event.UinputControlCode.forEventType(entry.getKey());
+ final int[] eventCodes = hexStringBitmapToEventCodes(entry.getValue());
+ if (controlCode != null && eventCodes.length > 0) {
+ config.append(controlCode.getValue(), eventCodes);
+ eventTypesToSet.add(entry.getKey());
+ }
+ }
+ config.append(
+ Event.UinputControlCode.UI_SET_EVBIT.getValue(), unboxIntList(eventTypesToSet));
+ }
+
+ private SparseArray<InputAbsInfo> parseAbsInfos() throws IOException {
+ final SparseArray<InputAbsInfo> absInfos = new SparseArray<>();
+ String line = acceptLine("A");
+ while (line != null) {
+ final String[] parts = line.strip().split(" ");
+ if (parts.length < 5 || parts.length > 6) {
+ throw new RuntimeException(
+ "'A:' lines should have the format 'A: <index (hex)> <min> <max> <fuzz> "
+ + "<flat> [<resolution>]'; expected 5 or 6 numbers but found "
+ + parts.length);
+ }
+ final int axisCode = Integer.parseInt(parts[0], 16);
+ final InputAbsInfo info = new InputAbsInfo();
+ info.minimum = Integer.parseInt(parts[1]);
+ info.maximum = Integer.parseInt(parts[2]);
+ info.fuzz = Integer.parseInt(parts[3]);
+ info.flat = Integer.parseInt(parts[4]);
+ info.resolution = parts.length > 5 ? Integer.parseInt(parts[5]) : 0;
+ absInfos.append(axisCode, info);
+ line = acceptLine("A");
+ }
+ return absInfos;
+ }
+
+ private void skipUnsupportedLines(String type) throws IOException {
+ if (acceptLine(type) != null) {
+ while (acceptLine(type) != null) {
+ // Skip the line.
+ }
+ }
+ }
+
+ /**
+ * Returns the contents of the next line in the file if it has the given type, or raises an
+ * error if it does not.
+ *
+ * @param type the type of the line to expect, represented by the letter before the ':'.
+ * @return the part of the line after the ": ".
+ */
+ private String expectLine(String type) throws IOException {
+ final String line = acceptLine(type);
+ if (line == null) {
+ throw new RuntimeException("Expected line of type '" + type + "'");
+ } else {
+ return line;
+ }
+ }
+
+ /**
+ * Peeks at the next line in the file to see if it has the given type, and if so, returns its
+ * contents and advances the reader.
+ *
+ * @param type the type of the line to accept, represented by the letter before the ':'.
+ * @return the part of the line after the ": ", if the type matches; otherwise {@code null}.
+ */
+ private @Nullable String acceptLine(String type) throws IOException {
+ final String line = mReader.peekLine();
+ if (line == null) {
+ return null;
+ }
+ final String[] lineParts = line.split(": ", 2);
+ if (lineParts.length < 2) {
+ // TODO(b/302297266): make a proper exception class for syntax errors, including line
+ // numbers, etc.. (We can use LineNumberReader to track them.)
+ throw new RuntimeException("Line without ': '");
+ }
+ if (lineParts[0].equals(type)) {
+ mReader.advance();
+ return lineParts[1];
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Like {@link #expectLine(String)}, but also checks that the contents of the line is formed of
+ * {@code numParts} space-separated parts.
+ *
+ * @param type the type of the line to expect, represented by the letter before the ':'.
+ * @param numParts the number of parts to expect.
+ * @return the part of the line after the ": ", split into {@code numParts} sections.
+ */
+ private String[] expectLineWithParts(String type, int numParts) throws IOException {
+ final String[] parts = expectLine(type).strip().split(" ");
+ if (parts.length != numParts) {
+ throw new RuntimeException("Expected a '" + type + "' line with " + numParts
+ + " parts, found one with " + parts.length);
+ }
+ return parts;
+ }
+
+ private static int[] hexStringBitmapToEventCodes(List<String> strs) {
+ final List<Integer> codes = new ArrayList<>();
+ for (int iByte = 0; iByte < strs.size(); iByte++) {
+ int b = Integer.parseInt(strs.get(iByte), 16);
+ if (b < 0x0 || b > 0xff) {
+ throw new RuntimeException("Bitmap part '" + strs.get(iByte)
+ + "' invalid; parts must be between 00 and ff.");
+ }
+ for (int iBit = 0; iBit < 8; iBit++) {
+ if ((b & 1) != 0) {
+ codes.add(iByte * 8 + iBit);
+ }
+ b >>= 1;
+ }
+ }
+ return unboxIntList(codes);
+ }
+
+ private static int[] unboxIntList(List<Integer> list) {
+ final int[] array = new int[list.size()];
+ Arrays.setAll(array, list::get);
+ return array;
+ }
+}
diff --git a/cmds/uinput/src/com/android/commands/uinput/Event.java b/cmds/uinput/src/com/android/commands/uinput/Event.java
index 4498bc2..5ec40e5 100644
--- a/cmds/uinput/src/com/android/commands/uinput/Event.java
+++ b/cmds/uinput/src/com/android/commands/uinput/Event.java
@@ -16,6 +16,7 @@
package com.android.commands.uinput;
+import android.annotation.Nullable;
import android.util.SparseArray;
import java.util.Arrays;
@@ -39,6 +40,7 @@
// Constants representing evdev event types, from include/uapi/linux/input-event-codes.h in the
// kernel.
+ public static final int EV_SYN = 0x00;
public static final int EV_KEY = 0x01;
public static final int EV_REL = 0x02;
public static final int EV_ABS = 0x03;
@@ -69,19 +71,23 @@
public int getValue() {
return mValue;
}
- }
- // These constants come from "include/uapi/linux/input.h" in the kernel
- enum Bus {
- USB(0x03), BLUETOOTH(0x05);
- private final int mValue;
-
- Bus(int value) {
- mValue = value;
- }
-
- int getValue() {
- return mValue;
+ /**
+ * Returns the control code for the given evdev event type, or {@code null} if there is no
+ * control code for that type.
+ */
+ public static @Nullable UinputControlCode forEventType(int eventType) {
+ return switch (eventType) {
+ case EV_KEY -> UI_SET_KEYBIT;
+ case EV_REL -> UI_SET_RELBIT;
+ case EV_ABS -> UI_SET_ABSBIT;
+ case EV_MSC -> UI_SET_MSCBIT;
+ case EV_SW -> UI_SET_SWBIT;
+ case EV_LED -> UI_SET_LEDBIT;
+ case EV_SND -> UI_SET_SNDBIT;
+ case EV_FF -> UI_SET_FFBIT;
+ default -> null;
+ };
}
}
@@ -90,7 +96,7 @@
private String mName;
private int mVid;
private int mPid;
- private Bus mBus;
+ private int mBusId;
private int[] mInjections;
private SparseArray<int[]> mConfiguration;
private int mDurationMillis;
@@ -120,7 +126,7 @@
}
public int getBus() {
- return mBus.getValue();
+ return mBusId;
}
public int[] getInjections() {
@@ -168,7 +174,7 @@
+ ", name=" + mName
+ ", vid=" + mVid
+ ", pid=" + mPid
- + ", bus=" + mBus
+ + ", busId=" + mBusId
+ ", events=" + Arrays.toString(mInjections)
+ ", configuration=" + mConfiguration
+ ", duration=" + mDurationMillis + "ms"
@@ -218,8 +224,8 @@
mEvent.mPid = pid;
}
- public void setBus(Bus bus) {
- mEvent.mBus = bus;
+ public void setBusId(int busId) {
+ mEvent.mBusId = busId;
}
public void setDurationMillis(int durationMillis) {
diff --git a/cmds/uinput/src/com/android/commands/uinput/EventParser.java b/cmds/uinput/src/com/android/commands/uinput/EventParser.java
new file mode 100644
index 0000000..a4df03d
--- /dev/null
+++ b/cmds/uinput/src/com/android/commands/uinput/EventParser.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 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.commands.uinput;
+
+import java.io.IOException;
+
+/**
+ * Interface for a class that reads a stream of {@link Event}s.
+ */
+public interface EventParser {
+ /**
+ * Returns the next event in the file that the parser is reading from.
+ */
+ Event getNextEvent() throws IOException;
+}
diff --git a/cmds/uinput/src/com/android/commands/uinput/JsonStyleParser.java b/cmds/uinput/src/com/android/commands/uinput/JsonStyleParser.java
index a2195c7..888ec5a 100644
--- a/cmds/uinput/src/com/android/commands/uinput/JsonStyleParser.java
+++ b/cmds/uinput/src/com/android/commands/uinput/JsonStyleParser.java
@@ -22,7 +22,7 @@
import android.util.SparseArray;
import java.io.IOException;
-import java.io.InputStreamReader;
+import java.io.Reader;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
@@ -34,12 +34,12 @@
/**
* A class that parses the JSON-like event format described in the README to build {@link Event}s.
*/
-public class JsonStyleParser {
+public class JsonStyleParser implements EventParser {
private static final String TAG = "UinputJsonStyleParser";
private JsonReader mReader;
- public JsonStyleParser(InputStreamReader in) {
+ public JsonStyleParser(Reader in) {
mReader = new JsonReader(in);
mReader.setLenient(true);
}
@@ -62,7 +62,7 @@
case "name" -> eb.setName(mReader.nextString());
case "vid" -> eb.setVid(readInt());
case "pid" -> eb.setPid(readInt());
- case "bus" -> eb.setBus(readBus());
+ case "bus" -> eb.setBusId(readBus());
case "events" -> {
int[] injections = readInjectedEvents().stream()
.mapToInt(Integer::intValue).toArray();
@@ -139,9 +139,35 @@
});
}
- private Event.Bus readBus() throws IOException {
+ private int readBus() throws IOException {
String val = mReader.nextString();
- return Event.Bus.valueOf(val.toUpperCase());
+ // See include/uapi/linux/input.h in the kernel for the source of these constants.
+ return switch (val.toUpperCase()) {
+ case "PCI" -> 0x01;
+ case "ISAPNP" -> 0x02;
+ case "USB" -> 0x03;
+ case "HIL" -> 0x04;
+ case "BLUETOOTH" -> 0x05;
+ case "VIRTUAL" -> 0x06;
+ case "ISA" -> 0x10;
+ case "I8042" -> 0x11;
+ case "XTKBD" -> 0x12;
+ case "RS232" -> 0x13;
+ case "GAMEPORT" -> 0x14;
+ case "PARPORT" -> 0x15;
+ case "AMIGA" -> 0x16;
+ case "ADB" -> 0x17;
+ case "I2C" -> 0x18;
+ case "HOST" -> 0x19;
+ case "GSC" -> 0x1A;
+ case "ATARI" -> 0x1B;
+ case "SPI" -> 0x1C;
+ case "RMI" -> 0x1D;
+ case "CEC" -> 0x1E;
+ case "INTEL_ISHTP" -> 0x1F;
+ case "AMD_SFH" -> 0x20;
+ default -> throw new IllegalArgumentException("Invalid bus ID " + val);
+ };
}
private SparseArray<int[]> readConfiguration()
diff --git a/cmds/uinput/src/com/android/commands/uinput/Uinput.java b/cmds/uinput/src/com/android/commands/uinput/Uinput.java
index fe76abb..684a12f 100644
--- a/cmds/uinput/src/com/android/commands/uinput/Uinput.java
+++ b/cmds/uinput/src/com/android/commands/uinput/Uinput.java
@@ -19,12 +19,12 @@
import android.util.Log;
import android.util.SparseArray;
+import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
-import java.io.UnsupportedEncodingException;
import java.util.Objects;
/**
@@ -35,7 +35,7 @@
public class Uinput {
private static final String TAG = "UINPUT";
- private final JsonStyleParser mParser;
+ private final EventParser mParser;
private final SparseArray<Device> mDevices;
private static void usage() {
@@ -74,12 +74,32 @@
private Uinput(InputStream in) {
mDevices = new SparseArray<Device>();
try {
- mParser = new JsonStyleParser(new InputStreamReader(in, "UTF-8"));
- } catch (UnsupportedEncodingException e) {
+ BufferedReader reader = new BufferedReader(new InputStreamReader(in, "UTF-8"));
+ mParser = isEvemuFile(reader) ? new EvemuParser(reader) : new JsonStyleParser(reader);
+ } catch (IOException e) {
throw new RuntimeException(e);
}
}
+ private boolean isEvemuFile(BufferedReader in) throws IOException {
+ // After zero or more empty lines (not even containing horizontal whitespace), evemu
+ // recordings must either start with '#' (indicating the EVEMU version header or a comment)
+ // or 'N' (for the name line). If we encounter anything else, assume it's a JSON-style input
+ // file.
+
+ String lineSep = System.lineSeparator();
+ char[] buf = new char[1];
+
+ in.mark(1 /* readAheadLimit */);
+ int charsRead = in.read(buf);
+ while (charsRead > 0 && lineSep.contains(String.valueOf(buf[0]))) {
+ in.mark(1 /* readAheadLimit */);
+ charsRead = in.read(buf);
+ }
+ in.reset();
+ return buf[0] == '#' || buf[0] == 'N';
+ }
+
private void run() {
try {
Event e = null;
diff --git a/cmds/uinput/tests/Android.bp b/cmds/uinput/tests/Android.bp
new file mode 100644
index 0000000..e728bd2
--- /dev/null
+++ b/cmds/uinput/tests/Android.bp
@@ -0,0 +1,20 @@
+package {
+ default_applicable_licenses: ["frameworks_base_cmds_uinput_license"],
+}
+
+android_test {
+ name: "UinputTests",
+ srcs: [
+ "src/**/*.java",
+ ],
+ static_libs: [
+ "androidx.test.runner",
+ "frameworks-base-testutils",
+ "platform-test-annotations",
+ "truth",
+ "uinput",
+ ],
+ test_suites: [
+ "device-tests",
+ ],
+}
diff --git a/cmds/uinput/tests/AndroidManifest.xml b/cmds/uinput/tests/AndroidManifest.xml
new file mode 100644
index 0000000..c364c1c
--- /dev/null
+++ b/cmds/uinput/tests/AndroidManifest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.commands.uinput.tests">
+
+ <application android:debuggable="true">
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation
+ android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:label="Uinput Tests"
+ android:targetPackage="com.android.commands.uinput.tests" />
+</manifest>
diff --git a/cmds/uinput/tests/src/com/android/commands/uinput/tests/EvemuParserTest.java b/cmds/uinput/tests/src/com/android/commands/uinput/tests/EvemuParserTest.java
new file mode 100644
index 0000000..6ee987f
--- /dev/null
+++ b/cmds/uinput/tests/src/com/android/commands/uinput/tests/EvemuParserTest.java
@@ -0,0 +1,476 @@
+/*
+ * Copyright 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.commands.uinput.tests;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import android.platform.test.annotations.Postsubmit;
+import android.util.SparseArray;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.commands.uinput.EvemuParser;
+import com.android.commands.uinput.Event;
+import com.android.commands.uinput.Event.UinputControlCode;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.IOException;
+import java.io.StringReader;
+
+import src.com.android.commands.uinput.InputAbsInfo;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+@Postsubmit
+public class EvemuParserTest {
+
+ private Event getRegistrationEvent(String fileContents) throws IOException {
+ StringReader reader = new StringReader(fileContents);
+ EvemuParser parser = new EvemuParser(reader);
+ Event event = parser.getNextEvent();
+ assertThat(event.getCommand()).isEqualTo(Event.Command.REGISTER);
+ return event;
+ }
+
+ @Test
+ public void testNameParsing() throws IOException {
+ Event event = getRegistrationEvent("""
+ N: ACME Pointing Widget #4
+ I: 0001 1234 5678 9abc
+ """);
+ assertThat(event.getName()).isEqualTo("ACME Pointing Widget #4");
+ }
+
+ @Test
+ public void testIdParsing() throws IOException {
+ Event event = getRegistrationEvent("""
+ N: ACME Pointing Widget #4
+ I: 0001 1234 5678 9abc
+ """);
+ assertThat(event.getBus()).isEqualTo(0x0001);
+ assertThat(event.getVendorId()).isEqualTo(0x1234);
+ assertThat(event.getProductId()).isEqualTo(0x5678);
+ // TODO(b/302297266): check version ID once it's supported
+ }
+
+ @Test
+ public void testPropertyBitmapParsing() throws IOException {
+ Event event = getRegistrationEvent("""
+ N: ACME Pointing Widget #4
+ I: 0001 1234 5678 9abc
+ P: 05 00 00 00 00 00 00 00
+ P: 01
+ """);
+ assertThat(event.getConfiguration().get(UinputControlCode.UI_SET_PROPBIT.getValue()))
+ .asList().containsExactly(0, 2, 64);
+ }
+
+ @Test
+ public void testEventBitmapParsing() throws IOException {
+ Event event = getRegistrationEvent("""
+ N: ACME Pointing Widget #4
+ I: 0001 1234 5678 9abc
+ B: 00 0b 00 00 00 00 00 00 00 # SYN
+ B: 01 00 00 03 00 00 00 00 00 # KEY
+ B: 01 00 01 00 00 00 00 00 00
+ B: 02 03 00 00 00 00 00 00 00 # REL
+ B: 03 00 00 # ABS
+ """);
+ assertThat(event.getConfiguration().get(UinputControlCode.UI_SET_EVBIT.getValue()))
+ .asList().containsExactly(Event.EV_KEY, Event.EV_REL);
+ assertThat(event.getConfiguration().get(UinputControlCode.UI_SET_KEYBIT.getValue()))
+ .asList().containsExactly(16, 17, 72);
+ assertThat(event.getConfiguration().get(UinputControlCode.UI_SET_RELBIT.getValue()))
+ .asList().containsExactly(0, 1);
+ assertThat(event.getConfiguration().contains(UinputControlCode.UI_SET_ABSBIT.getValue()))
+ .isFalse();
+ }
+
+ @Test
+ public void testEventBitmapParsing_WithForceFeedback() throws IOException {
+ Event event = getRegistrationEvent("""
+ N: ACME Pointing Widget #4
+ I: 0001 1234 5678 9abc
+ B: 15 05 # FF
+ """);
+ assertThat(event.getConfiguration().get(UinputControlCode.UI_SET_EVBIT.getValue()))
+ .asList().containsExactly(Event.EV_FF);
+ assertThat(event.getConfiguration().get(UinputControlCode.UI_SET_FFBIT.getValue()))
+ .asList().containsExactly(0, 2);
+ assertThat(event.getFfEffectsMax()).isEqualTo(2);
+ }
+
+ private void assertAbsInfo(InputAbsInfo info, int minimum, int maximum, int fuzz, int flat,
+ int resolution) {
+ assertThat(info).isNotNull();
+ assertWithMessage("Incorrect minimum").that(info.minimum).isEqualTo(minimum);
+ assertWithMessage("Incorrect maximum").that(info.maximum).isEqualTo(maximum);
+ assertWithMessage("Incorrect fuzz").that(info.fuzz).isEqualTo(fuzz);
+ assertWithMessage("Incorrect flat").that(info.flat).isEqualTo(flat);
+ assertWithMessage("Incorrect resolution").that(info.resolution).isEqualTo(resolution);
+ }
+
+ @Test
+ public void testAbsInfoParsing_WithResolution() throws IOException {
+ Event event = getRegistrationEvent("""
+ N: ACME Weird Gamepad
+ I: 0001 1234 5678 9abc
+ A: 03 -128 128 4 4 0 # ABS_MT_RX
+ A: 2f 0 9 0 0 0 # ABS_MT_SLOT
+ A: 34 -4096 4096 0 0 0 # ABS_MT_ORIENTATION
+ A: 35 0 1599 0 0 11 # ABS_MT_POSITION_X
+ """);
+ SparseArray<InputAbsInfo> absInfos = event.getAbsInfo();
+ assertThat(absInfos.size()).isEqualTo(4);
+ assertAbsInfo(absInfos.get(0x03), -128, 128, 4, 4, 0);
+ assertAbsInfo(absInfos.get(0x2f), 0, 9, 0, 0, 0);
+ assertAbsInfo(absInfos.get(0x34), -4096, 4096, 0, 0, 0);
+ assertAbsInfo(absInfos.get(0x35), 0, 1599, 0, 0, 11);
+ }
+
+ @Test
+ public void testAbsInfoParsing_WithoutResolution() throws IOException {
+ Event event = getRegistrationEvent("""
+ N: ACME Terrible Touchscreen
+ I: 0001 1234 5678 9abc
+ A: 2f 0 9 0 0 # ABS_MT_SLOT
+ A: 35 0 1599 0 0 # ABS_MT_POSITION_X
+ A: 36 0 2559 0 0 # ABS_MT_POSITION_X
+ """);
+ SparseArray<InputAbsInfo> absInfos = event.getAbsInfo();
+ assertThat(absInfos.size()).isEqualTo(3);
+ assertAbsInfo(absInfos.get(0x2f), 0, 9, 0, 0, 0);
+ assertAbsInfo(absInfos.get(0x35), 0, 1599, 0, 0, 0);
+ assertAbsInfo(absInfos.get(0x36), 0, 2559, 0, 0, 0);
+ }
+
+ @Test
+ public void testLedAndSwitchStatesIgnored() throws IOException {
+ // We don't support L: and S: lines yet, so all we need to check here is that they don't
+ // prevent the other events from being parsed.
+ StringReader reader = new StringReader("""
+ N: ACME Widget
+ I: 0001 1234 5678 9abc
+ L: 00 0
+ L: 09 1
+ S: 0a 1
+ E: 0.000001 0 0 0 # SYN_REPORT
+ """);
+ EvemuParser parser = new EvemuParser(reader);
+ assertThat(parser.getNextEvent().getCommand()).isEqualTo(Event.Command.REGISTER);
+ assertThat(parser.getNextEvent().getCommand()).isEqualTo(Event.Command.DELAY);
+ assertThat(parser.getNextEvent().getCommand()).isEqualTo(Event.Command.INJECT);
+ }
+
+ private void assertInjectEvent(Event event, int eventType, int eventCode, int value) {
+ assertThat(event).isNotNull();
+ assertThat(event.getCommand()).isEqualTo(Event.Command.INJECT);
+ assertThat(event.getInjections()).asList()
+ .containsExactly(eventType, eventCode, value).inOrder();
+ }
+
+ private void assertDelayEvent(Event event, int durationMillis) {
+ assertThat(event).isNotNull();
+ assertThat(event.getCommand()).isEqualTo(Event.Command.DELAY);
+ assertThat(event.getDurationMillis()).isEqualTo(durationMillis);
+ }
+
+ @Test
+ public void testEventParsing_OneFrame() throws IOException {
+ StringReader reader = new StringReader("""
+ N: ACME Widget
+ I: 0001 1234 5678 9abc
+ E: 0.000001 0002 0000 0001 # REL_X +1
+ E: 0.000001 0002 0001 -0002 # REL_Y -2
+ E: 0.000001 0000 0000 0000 # SYN_REPORT
+ """);
+ EvemuParser parser = new EvemuParser(reader);
+ assertThat(parser.getNextEvent().getCommand()).isEqualTo(Event.Command.REGISTER);
+ assertThat(parser.getNextEvent().getCommand()).isEqualTo(Event.Command.DELAY);
+ assertInjectEvent(parser.getNextEvent(), 0x2, 0x0, 1);
+ assertInjectEvent(parser.getNextEvent(), 0x2, 0x1, -2);
+ assertInjectEvent(parser.getNextEvent(), 0x0, 0x0, 0);
+ }
+
+ @Test
+ public void testEventParsing_MultipleFrames() throws IOException {
+ StringReader reader = new StringReader("""
+ N: ACME YesBird Typing Aid
+ I: 0001 1234 5678 9abc
+ E: 0.000001 0001 0015 0001 # KEY_Y press
+ E: 0.000001 0000 0000 0000 # SYN_REPORT
+ E: 0.010001 0001 0015 0000 # KEY_Y release
+ E: 0.010001 0000 0000 0000 # SYN_REPORT
+ E: 1.010001 0001 0015 0001 # KEY_Y press
+ E: 1.010001 0000 0000 0000 # SYN_REPORT
+ """);
+ EvemuParser parser = new EvemuParser(reader);
+ assertThat(parser.getNextEvent().getCommand()).isEqualTo(Event.Command.REGISTER);
+ assertThat(parser.getNextEvent().getCommand()).isEqualTo(Event.Command.DELAY);
+
+ assertInjectEvent(parser.getNextEvent(), 0x1, 0x15, 1);
+ assertInjectEvent(parser.getNextEvent(), 0x0, 0x0, 0);
+
+ assertDelayEvent(parser.getNextEvent(), 10);
+
+ assertInjectEvent(parser.getNextEvent(), 0x1, 0x15, 0);
+ assertInjectEvent(parser.getNextEvent(), 0x0, 0x0, 0);
+
+ assertDelayEvent(parser.getNextEvent(), 1000);
+
+ assertInjectEvent(parser.getNextEvent(), 0x1, 0x15, 1);
+ assertInjectEvent(parser.getNextEvent(), 0x0, 0x0, 0);
+ }
+
+ @Test
+ public void testFreeDesktopEvemuRecording() throws IOException {
+ // This is a real recording from FreeDesktop's evemu-record tool, as a basic compatibility
+ // check with the FreeDesktop tools.
+ // (CheckStyle objects to the long line here. It can be split up with escaped newlines once
+ // the fix for b/306423115 reaches Android.)
+ StringReader reader = new StringReader("""
+ # EVEMU 1.3
+ # Kernel: 6.5.6-1rodete4-amd64
+ # DMI: dmi:bvnLENOVO:bvrXXXXXXXX(X.XX):bdXX/XX/XXXX:brX.XX:efrX.XX:svnLENOVO:pnXXXXXXXXXX:pvrThinkPadX1Carbon:rvnLENOVO:rnXXXXXXXXX:rvrXXXXX:cvnLENOVO:ctXX:cvrNone:skuLENOVO_MT_20KG_BU_Think_FM_ThinkPadX1Carbon:
+ # Input device name: "Synaptics TM3289-021"
+ # Input device ID: bus 0x1d vendor 0x6cb product 0000 version 0000
+ # Size in mm: 96x52
+ # Supported events:
+ # Event type 0 (EV_SYN)
+ # Event code 0 (SYN_REPORT)
+ # Event code 1 (SYN_CONFIG)
+ # Event code 2 (SYN_MT_REPORT)
+ # Event code 3 (SYN_DROPPED)
+ # Event code 4 ((null))
+ # Event code 5 ((null))
+ # Event code 6 ((null))
+ # Event code 7 ((null))
+ # Event code 8 ((null))
+ # Event code 9 ((null))
+ # Event code 10 ((null))
+ # Event code 11 ((null))
+ # Event code 12 ((null))
+ # Event code 13 ((null))
+ # Event code 14 ((null))
+ # Event code 15 (SYN_MAX)
+ # Event type 1 (EV_KEY)
+ # Event code 272 (BTN_LEFT)
+ # Event code 325 (BTN_TOOL_FINGER)
+ # Event code 328 (BTN_TOOL_QUINTTAP)
+ # Event code 330 (BTN_TOUCH)
+ # Event code 333 (BTN_TOOL_DOUBLETAP)
+ # Event code 334 (BTN_TOOL_TRIPLETAP)
+ # Event code 335 (BTN_TOOL_QUADTAP)
+ # Event type 3 (EV_ABS)
+ # Event code 0 (ABS_X)
+ # Value 0
+ # Min 0
+ # Max 1936
+ # Fuzz 0
+ # Flat 0
+ # Resolution 20
+ # Event code 1 (ABS_Y)
+ # Value 0
+ # Min 0
+ # Max 1057
+ # Fuzz 0
+ # Flat 0
+ # Resolution 20
+ # Event code 24 (ABS_PRESSURE)
+ # Value 0
+ # Min 0
+ # Max 255
+ # Fuzz 0
+ # Flat 0
+ # Resolution 0
+ # Event code 47 (ABS_MT_SLOT)
+ # Value 0
+ # Min 0
+ # Max 4
+ # Fuzz 0
+ # Flat 0
+ # Resolution 0
+ # Event code 48 (ABS_MT_TOUCH_MAJOR)
+ # Value 0
+ # Min 0
+ # Max 15
+ # Fuzz 0
+ # Flat 0
+ # Resolution 0
+ # Event code 49 (ABS_MT_TOUCH_MINOR)
+ # Value 0
+ # Min 0
+ # Max 15
+ # Fuzz 0
+ # Flat 0
+ # Resolution 0
+ # Event code 52 (ABS_MT_ORIENTATION)
+ # Value 0
+ # Min 0
+ # Max 1
+ # Fuzz 0
+ # Flat 0
+ # Resolution 0
+ # Event code 53 (ABS_MT_POSITION_X)
+ # Value 0
+ # Min 0
+ # Max 1936
+ # Fuzz 0
+ # Flat 0
+ # Resolution 20
+ # Event code 54 (ABS_MT_POSITION_Y)
+ # Value 0
+ # Min 0
+ # Max 1057
+ # Fuzz 0
+ # Flat 0
+ # Resolution 20
+ # Event code 55 (ABS_MT_TOOL_TYPE)
+ # Value 0
+ # Min 0
+ # Max 15
+ # Fuzz 0
+ # Flat 0
+ # Resolution 0
+ # Event code 57 (ABS_MT_TRACKING_ID)
+ # Value 0
+ # Min 0
+ # Max 65535
+ # Fuzz 0
+ # Flat 0
+ # Resolution 0
+ # Event code 58 (ABS_MT_PRESSURE)
+ # Value 0
+ # Min 0
+ # Max 255
+ # Fuzz 0
+ # Flat 0
+ # Resolution 0
+ # Properties:
+ # Property type 0 (INPUT_PROP_POINTER)
+ # Property type 2 (INPUT_PROP_BUTTONPAD)
+ N: Synaptics TM3289-021
+ I: 001d 06cb 0000 0000
+ P: 05 00 00 00 00 00 00 00
+ B: 00 0b 00 00 00 00 00 00 00
+ B: 01 00 00 00 00 00 00 00 00
+ B: 01 00 00 00 00 00 00 00 00
+ B: 01 00 00 00 00 00 00 00 00
+ B: 01 00 00 00 00 00 00 00 00
+ B: 01 00 00 01 00 00 00 00 00
+ B: 01 20 e5 00 00 00 00 00 00
+ B: 01 00 00 00 00 00 00 00 00
+ B: 01 00 00 00 00 00 00 00 00
+ B: 01 00 00 00 00 00 00 00 00
+ B: 01 00 00 00 00 00 00 00 00
+ B: 01 00 00 00 00 00 00 00 00
+ B: 01 00 00 00 00 00 00 00 00
+ B: 02 00 00 00 00 00 00 00 00
+ B: 03 03 00 00 01 00 80 f3 06
+ B: 04 00 00 00 00 00 00 00 00
+ B: 05 00 00 00 00 00 00 00 00
+ B: 11 00 00 00 00 00 00 00 00
+ B: 12 00 00 00 00 00 00 00 00
+ B: 14 00 00 00 00 00 00 00 00
+ B: 15 00 00 00 00 00 00 00 00
+ B: 15 00 00 00 00 00 00 00 00
+ A: 00 0 1936 0 0 20
+ A: 01 0 1057 0 0 20
+ A: 18 0 255 0 0 0
+ A: 2f 0 4 0 0 0
+ A: 30 0 15 0 0 0
+ A: 31 0 15 0 0 0
+ A: 34 0 1 0 0 0
+ A: 35 0 1936 0 0 20
+ A: 36 0 1057 0 0 20
+ A: 37 0 15 0 0 0
+ A: 39 0 65535 0 0 0
+ A: 3a 0 255 0 0 0
+ ################################
+ # Waiting for events #
+ ################################
+ E: 0.000001 0003 0039 0000\t# EV_ABS / ABS_MT_TRACKING_ID 0
+ E: 0.000001 0003 0035 0891\t# EV_ABS / ABS_MT_POSITION_X 891
+ E: 0.000001 0003 0036 0333\t# EV_ABS / ABS_MT_POSITION_Y 333
+ E: 0.000001 0003 003a 0056\t# EV_ABS / ABS_MT_PRESSURE 56
+ E: 0.000001 0003 0030 0001\t# EV_ABS / ABS_MT_TOUCH_MAJOR 1
+ E: 0.000001 0003 0031 0001\t# EV_ABS / ABS_MT_TOUCH_MINOR 1
+ E: 0.000001 0001 014a 0001\t# EV_KEY / BTN_TOUCH 1
+ E: 0.000001 0001 0145 0001\t# EV_KEY / BTN_TOOL_FINGER 1
+ E: 0.000001 0003 0000 0891\t# EV_ABS / ABS_X 891
+ E: 0.000001 0003 0001 0333\t# EV_ABS / ABS_Y 333
+ E: 0.000001 0003 0018 0056\t# EV_ABS / ABS_PRESSURE 56
+ E: 0.000001 0000 0000 0000\t# ------------ SYN_REPORT (0) ---------- +0ms
+ E: 0.006081 0003 0035 0888\t# EV_ABS / ABS_MT_POSITION_X 888
+ """);
+ EvemuParser parser = new EvemuParser(reader);
+ Event regEvent = parser.getNextEvent();
+ assertThat(regEvent.getName()).isEqualTo("Synaptics TM3289-021");
+
+ assertThat(regEvent.getBus()).isEqualTo(0x001d);
+ assertThat(regEvent.getVendorId()).isEqualTo(0x6cb);
+ assertThat(regEvent.getProductId()).isEqualTo(0x0000);
+ // TODO(b/302297266): check version ID once it's supported
+
+ assertThat(regEvent.getConfiguration().get(UinputControlCode.UI_SET_PROPBIT.getValue()))
+ .asList().containsExactly(0, 2);
+
+ assertThat(regEvent.getConfiguration().get(UinputControlCode.UI_SET_EVBIT.getValue()))
+ .asList().containsExactly(Event.EV_KEY, Event.EV_ABS);
+ assertThat(regEvent.getConfiguration().get(UinputControlCode.UI_SET_KEYBIT.getValue()))
+ .asList().containsExactly(272, 325, 328, 330, 333, 334, 335);
+ assertThat(regEvent.getConfiguration().get(UinputControlCode.UI_SET_ABSBIT.getValue()))
+ .asList().containsExactly(0, 1, 24, 47, 48, 49, 52, 53, 54, 55, 57, 58);
+
+ SparseArray<InputAbsInfo> absInfos = regEvent.getAbsInfo();
+ assertAbsInfo(absInfos.get(0), 0, 1936, 0, 0, 20);
+ assertAbsInfo(absInfos.get(1), 0, 1057, 0, 0, 20);
+ assertAbsInfo(absInfos.get(24), 0, 255, 0, 0, 0);
+ assertAbsInfo(absInfos.get(47), 0, 4, 0, 0, 0);
+ assertAbsInfo(absInfos.get(48), 0, 15, 0, 0, 0);
+ assertAbsInfo(absInfos.get(49), 0, 15, 0, 0, 0);
+ assertAbsInfo(absInfos.get(52), 0, 1, 0, 0, 0);
+ assertAbsInfo(absInfos.get(53), 0, 1936, 0, 0, 20);
+ assertAbsInfo(absInfos.get(54), 0, 1057, 0, 0, 20);
+ assertAbsInfo(absInfos.get(55), 0, 15, 0, 0, 0);
+ assertAbsInfo(absInfos.get(57), 0, 65535, 0, 0, 0);
+ assertAbsInfo(absInfos.get(58), 0, 255, 0, 0, 0);
+
+ assertThat(parser.getNextEvent().getCommand()).isEqualTo(Event.Command.DELAY);
+
+ assertInjectEvent(parser.getNextEvent(), 0x3, 0x39, 0);
+ assertInjectEvent(parser.getNextEvent(), 0x3, 0x35, 891);
+ assertInjectEvent(parser.getNextEvent(), 0x3, 0x36, 333);
+ assertInjectEvent(parser.getNextEvent(), 0x3, 0x3a, 56);
+ assertInjectEvent(parser.getNextEvent(), 0x3, 0x30, 1);
+ assertInjectEvent(parser.getNextEvent(), 0x3, 0x31, 1);
+ assertInjectEvent(parser.getNextEvent(), 0x1, 0x14a, 1);
+ assertInjectEvent(parser.getNextEvent(), 0x1, 0x145, 1);
+ assertInjectEvent(parser.getNextEvent(), 0x3, 0x0, 891);
+ assertInjectEvent(parser.getNextEvent(), 0x3, 0x1, 333);
+ assertInjectEvent(parser.getNextEvent(), 0x3, 0x18, 56);
+ assertInjectEvent(parser.getNextEvent(), 0x0, 0x0, 0);
+
+ assertDelayEvent(parser.getNextEvent(), 6);
+
+ assertInjectEvent(parser.getNextEvent(), 0x3, 0x0035, 888);
+ }
+}
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 275fe77..c282e4b6 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -307,7 +307,7 @@
field public static final String RECOVER_KEYSTORE = "android.permission.RECOVER_KEYSTORE";
field public static final String REGISTER_CALL_PROVIDER = "android.permission.REGISTER_CALL_PROVIDER";
field public static final String REGISTER_CONNECTION_MANAGER = "android.permission.REGISTER_CONNECTION_MANAGER";
- field public static final String REGISTER_NSD_OFFLOAD_ENGINE = "android.permission.REGISTER_NSD_OFFLOAD_ENGINE";
+ field @FlaggedApi("com.android.net.flags.register_nsd_offload_engine") public static final String REGISTER_NSD_OFFLOAD_ENGINE = "android.permission.REGISTER_NSD_OFFLOAD_ENGINE";
field public static final String REGISTER_SIM_SUBSCRIPTION = "android.permission.REGISTER_SIM_SUBSCRIPTION";
field public static final String REGISTER_STATS_PULL_ATOM = "android.permission.REGISTER_STATS_PULL_ATOM";
field public static final String REMOTE_DISPLAY_PROVIDER = "android.permission.REMOTE_DISPLAY_PROVIDER";
diff --git a/core/java/android/accounts/Account.java b/core/java/android/accounts/Account.java
index c376eae..76735b6 100644
--- a/core/java/android/accounts/Account.java
+++ b/core/java/android/accounts/Account.java
@@ -38,6 +38,7 @@
* {@link Parcelable} and also overrides {@link #equals} and {@link #hashCode}, making it
* suitable for use as the key of a {@link java.util.Map}
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public class Account implements Parcelable {
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
private static final String TAG = "Account";
@@ -104,18 +105,27 @@
if (accessId != null) {
synchronized (sAccessedAccounts) {
if (sAccessedAccounts.add(this)) {
- try {
- IAccountManager accountManager = IAccountManager.Stub.asInterface(
- ServiceManager.getService(Context.ACCOUNT_SERVICE));
- accountManager.onAccountAccessed(accessId);
- } catch (RemoteException e) {
- Log.e(TAG, "Error noting account access", e);
- }
+ onAccountAccessed(accessId);
}
}
}
}
+ @android.ravenwood.annotation.RavenwoodReplace
+ private static void onAccountAccessed(String accessId) {
+ try {
+ IAccountManager accountManager = IAccountManager.Stub.asInterface(
+ ServiceManager.getService(Context.ACCOUNT_SERVICE));
+ accountManager.onAccountAccessed(accessId);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error noting account access", e);
+ }
+ }
+
+ private static void onAccountAccessed$ravenwood(String accessId) {
+ // No AccountManager to communicate with; ignored
+ }
+
/** @hide */
public String getAccessId() {
return accessId;
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index bb335fa..6c10f49 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -20,6 +20,7 @@
import static android.Manifest.permission.DETECT_SCREEN_CAPTURE;
import static android.Manifest.permission.INTERACT_ACROSS_USERS;
import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
+import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.inMultiWindowMode;
import static android.os.Process.myUid;
@@ -7603,15 +7604,17 @@
* @param taskDescription The TaskDescription properties that describe the task with this activity
*/
public void setTaskDescription(ActivityManager.TaskDescription taskDescription) {
- if (mTaskDescription != taskDescription) {
- mTaskDescription.copyFromPreserveHiddenFields(taskDescription);
- // Scale the icon down to something reasonable if it is provided
- if (taskDescription.getIconFilename() == null && taskDescription.getIcon() != null) {
- final int size = ActivityManager.getLauncherLargeIconSizeInner(this);
- final Bitmap icon = Bitmap.createScaledBitmap(taskDescription.getIcon(), size, size,
- true);
- mTaskDescription.setIcon(Icon.createWithBitmap(icon));
- }
+ if (taskDescription == null || mTaskDescription.equals(taskDescription)) {
+ return;
+ }
+
+ mTaskDescription.copyFromPreserveHiddenFields(taskDescription);
+ // Scale the icon down to something reasonable if it is provided
+ if (taskDescription.getIconFilename() == null && taskDescription.getIcon() != null) {
+ final int size = ActivityManager.getLauncherLargeIconSizeInner(this);
+ final Bitmap icon = Bitmap.createScaledBitmap(taskDescription.getIcon(), size, size,
+ true);
+ mTaskDescription.setIcon(Icon.createWithBitmap(icon));
}
ActivityClient.getInstance().setTaskDescription(mToken, mTaskDescription);
}
@@ -9439,6 +9442,15 @@
ActivityClient.getInstance().enableTaskLocaleOverride(mToken);
}
+ /**
+ * Request ActivityRecordInputSink to enable or disable blocking input events.
+ * @hide
+ */
+ @RequiresPermission(INTERNAL_SYSTEM_WINDOW)
+ public void setActivityRecordInputSinkEnabled(boolean enabled) {
+ ActivityClient.getInstance().setActivityRecordInputSinkEnabled(mToken, enabled);
+ }
+
class HostCallbacks extends FragmentHostCallback<Activity> {
public HostCallbacks() {
super(Activity.this /*activity*/);
diff --git a/core/java/android/app/ActivityClient.java b/core/java/android/app/ActivityClient.java
index b35e87b..b8bd030 100644
--- a/core/java/android/app/ActivityClient.java
+++ b/core/java/android/app/ActivityClient.java
@@ -16,6 +16,8 @@
package android.app;
+import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW;
+
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.content.ComponentName;
@@ -614,6 +616,15 @@
}
}
+ @RequiresPermission(INTERNAL_SYSTEM_WINDOW)
+ void setActivityRecordInputSinkEnabled(IBinder activityToken, boolean enabled) {
+ try {
+ getActivityClientController().setActivityRecordInputSinkEnabled(activityToken, enabled);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
+
/**
* Shows or hides a Camera app compat toggle for stretched issues with the requested state.
*
diff --git a/core/java/android/app/IActivityClientController.aidl b/core/java/android/app/IActivityClientController.aidl
index a3c5e1c..7370fc3 100644
--- a/core/java/android/app/IActivityClientController.aidl
+++ b/core/java/android/app/IActivityClientController.aidl
@@ -191,4 +191,14 @@
*/
boolean isRequestedToLaunchInTaskFragment(in IBinder activityToken,
in IBinder taskFragmentToken);
+
+ /**
+ * Enable or disable ActivityRecordInputSink to block input events.
+ *
+ * @param token The token for the activity that requests to toggle.
+ * @param enabled Whether the input evens are blocked by ActivityRecordInputSink.
+ */
+ @JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest"
+ + ".permission.INTERNAL_SYSTEM_WINDOW)")
+ oneway void setActivityRecordInputSinkEnabled(in IBinder activityToken, boolean enabled);
}
diff --git a/core/java/android/companion/utils/FeatureUtils.java b/core/java/android/companion/utils/FeatureUtils.java
deleted file mode 100644
index a382e09..0000000
--- a/core/java/android/companion/utils/FeatureUtils.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.companion.utils;
-
-import android.os.Binder;
-import android.os.Build;
-import android.provider.DeviceConfig;
-
-/**
- * Util class for feature flags
- *
- * @hide
- */
-public final class FeatureUtils {
-
- private static final String NAMESPACE_COMPANION = "companion";
-
- private static final String PROPERTY_PERM_SYNC_ENABLED = "perm_sync_enabled";
-
- public static boolean isPermSyncEnabled() {
- // Permissions sync is always enabled in debuggable mode.
- if (Build.isDebuggable()) {
- return true;
- }
-
- // Clear app identity to read the device config for feature flag.
- final long identity = Binder.clearCallingIdentity();
- try {
- return DeviceConfig.getBoolean(NAMESPACE_COMPANION,
- PROPERTY_PERM_SYNC_ENABLED, false);
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- }
-
- private FeatureUtils() {
- }
-}
diff --git a/core/java/android/companion/virtual/flags.aconfig b/core/java/android/companion/virtual/flags.aconfig
index 02066fa..10da8b1 100644
--- a/core/java/android/companion/virtual/flags.aconfig
+++ b/core/java/android/companion/virtual/flags.aconfig
@@ -1,3 +1,12 @@
+# Do not add new flags to this file.
+#
+# Due to "virtual" keyword in the package name flags
+# added to this file cannot be accessed from C++
+# code.
+#
+# Use frameworks/base/core/java/android/companion/virtual/flags/flags.aconfig
+# instead.
+
package: "android.companion.virtual.flags"
flag {
diff --git a/core/java/android/companion/virtual/flags/flags.aconfig b/core/java/android/companion/virtual/flags/flags.aconfig
new file mode 100644
index 0000000..d26890f
--- /dev/null
+++ b/core/java/android/companion/virtual/flags/flags.aconfig
@@ -0,0 +1,23 @@
+#
+# 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: "android.companion.virtualdevice.flags"
+
+flag {
+ namespace: "virtual_devices"
+ name: "virtual_camera_service_discovery"
+ description: "Enable discovery of the Virtual Camera HAL without a VINTF entry"
+ bug: "305170199"
+}
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 89f889f..fe95a2a 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -1414,7 +1414,7 @@
* otherwise the value will be equal to 1.
* Note that this level is just a number of supported levels (the granularity of control).
* There is no actual physical power units tied to this level.</p>
- * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
+ * <p>This key is available on all devices.</p>
*
* @see CaptureRequest#FLASH_MODE
*/
@@ -1430,7 +1430,7 @@
* or equal to <code>android.flash.info.singleStrengthMaxLevel</code>.
* Note for devices that do not support the manual flash strength control
* feature, this level will always be equal to 1.</p>
- * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
+ * <p>This key is available on all devices.</p>
*/
@PublicKey
@NonNull
@@ -1450,7 +1450,7 @@
* android.flash.info.singleStrengthMaxLevel i.e. the ratio of
* android.flash.info.torchStrengthMaxLevel:android.flash.info.singleStrengthMaxLevel
* is not guaranteed to be the ratio of actual brightness.</p>
- * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
+ * <p>This key is available on all devices.</p>
*
* @see CaptureRequest#FLASH_MODE
*/
@@ -1466,7 +1466,7 @@
* or equal to android.flash.info.torchStrengthMaxLevel.
* Note for the devices that do not support the manual flash strength control feature,
* this level will always be equal to 1.</p>
- * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
+ * <p>This key is available on all devices.</p>
*/
@PublicKey
@NonNull
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index 5d06978..93cae54 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -2688,7 +2688,7 @@
* set to TORCH;
* <code>[1-android.flash.info.singleStrengthMaxLevel]</code> when the {@link CaptureRequest#FLASH_MODE android.flash.mode} is
* set to SINGLE</p>
- * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
+ * <p>This key is available on all devices.</p>
*
* @see CaptureRequest#CONTROL_AE_MODE
* @see CaptureRequest#FLASH_MODE
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index 0d204f3..12ab0f6 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -2974,7 +2974,7 @@
* set to TORCH;
* <code>[1-android.flash.info.singleStrengthMaxLevel]</code> when the {@link CaptureRequest#FLASH_MODE android.flash.mode} is
* set to SINGLE</p>
- * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
+ * <p>This key is available on all devices.</p>
*
* @see CaptureRequest#CONTROL_AE_MODE
* @see CaptureRequest#FLASH_MODE
diff --git a/core/java/android/hardware/location/NanoAppMessage.java b/core/java/android/hardware/location/NanoAppMessage.java
index bb3e81a..7ac1dd1 100644
--- a/core/java/android/hardware/location/NanoAppMessage.java
+++ b/core/java/android/hardware/location/NanoAppMessage.java
@@ -56,6 +56,8 @@
*
* @param targetNanoAppId the ID of the nanoapp to send the message to
* @param messageType the nanoapp-dependent message type
+ * the value CHRE_MESSAGE_TYPE_RPC (0x7FFFFFF5) is reserved by the
+ * framework for RPC messages
* @param messageBody the byte array message contents
*
* @return the NanoAppMessage object
diff --git a/core/java/android/os/Handler.java b/core/java/android/os/Handler.java
index 22d6fcd..92b630f 100644
--- a/core/java/android/os/Handler.java
+++ b/core/java/android/os/Handler.java
@@ -63,6 +63,7 @@
* your new thread. The given Runnable or Message will then be scheduled
* in the Handler's message queue and processed when appropriate.
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public class Handler {
/*
* Set this flag to true to detect anonymous, local or member classes
diff --git a/core/java/android/os/HandlerThread.java b/core/java/android/os/HandlerThread.java
index 4dd797a..fcd5731 100644
--- a/core/java/android/os/HandlerThread.java
+++ b/core/java/android/os/HandlerThread.java
@@ -25,6 +25,7 @@
* <p>
* Note that just like with a regular {@link Thread}, {@link #start()} must still be called.
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public class HandlerThread extends Thread {
int mPriority;
int mTid = -1;
diff --git a/core/java/android/os/Looper.java b/core/java/android/os/Looper.java
index 712d328..ddf2b61 100644
--- a/core/java/android/os/Looper.java
+++ b/core/java/android/os/Looper.java
@@ -24,6 +24,8 @@
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
+import java.util.Objects;
+
/**
* Class used to run a message loop for a thread. Threads by default do
* not have a message loop associated with them; to create one, call
@@ -54,6 +56,7 @@
* }
* }</pre>
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public final class Looper {
/*
* API Implementation Note:
@@ -144,6 +147,30 @@
}
/**
+ * Force the application's main looper to the given value. The main looper is typically
+ * configured automatically by the OS, so this capability is only intended to enable testing.
+ *
+ * @hide
+ */
+ public static void setMainLooperForTest(@NonNull Looper looper) {
+ synchronized (Looper.class) {
+ sMainLooper = Objects.requireNonNull(looper);
+ }
+ }
+
+ /**
+ * Clear the application's main looper to be undefined. The main looper is typically
+ * configured automatically by the OS, so this capability is only intended to enable testing.
+ *
+ * @hide
+ */
+ public static void clearMainLooperForTest() {
+ synchronized (Looper.class) {
+ sMainLooper = null;
+ }
+ }
+
+ /**
* Set the transaction observer for all Loopers in this process.
*
* @hide
@@ -282,11 +309,7 @@
// Allow overriding a threshold with a system prop. e.g.
// adb shell 'setprop log.looper.1000.main.slow 1 && stop && start'
- final int thresholdOverride =
- SystemProperties.getInt("log.looper."
- + Process.myUid() + "."
- + Thread.currentThread().getName()
- + ".slow", -1);
+ final int thresholdOverride = getThresholdOverride();
me.mSlowDeliveryDetected = false;
@@ -297,6 +320,18 @@
}
}
+ @android.ravenwood.annotation.RavenwoodReplace
+ private static int getThresholdOverride() {
+ return SystemProperties.getInt("log.looper."
+ + Process.myUid() + "."
+ + Thread.currentThread().getName()
+ + ".slow", -1);
+ }
+
+ private static int getThresholdOverride$ravenwood() {
+ return -1;
+ }
+
private static boolean showSlowLog(long threshold, long measureStart, long measureEnd,
String what, Message msg) {
final long actualTime = measureEnd - measureStart;
diff --git a/core/java/android/os/Message.java b/core/java/android/os/Message.java
index 72fb4ae..da647e2 100644
--- a/core/java/android/os/Message.java
+++ b/core/java/android/os/Message.java
@@ -33,6 +33,7 @@
* {@link Handler#obtainMessage Handler.obtainMessage()} methods, which will pull
* them from a pool of recycled objects.</p>
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public final class Message implements Parcelable {
/**
* User-defined message code so that the recipient can identify
diff --git a/core/java/android/os/MessageQueue.java b/core/java/android/os/MessageQueue.java
index 9d8a71b..c60f949 100644
--- a/core/java/android/os/MessageQueue.java
+++ b/core/java/android/os/MessageQueue.java
@@ -40,6 +40,9 @@
* <p>You can retrieve the MessageQueue for the current thread with
* {@link Looper#myQueue() Looper.myQueue()}.
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
+@android.ravenwood.annotation.RavenwoodNativeSubstitutionClass(
+ "com.android.hoststubgen.nativesubstitution.MessageQueue_host")
public final class MessageQueue {
private static final String TAG = "MessageQueue";
private static final boolean DEBUG = false;
@@ -194,6 +197,7 @@
* @see OnFileDescriptorEventListener
* @see #removeOnFileDescriptorEventListener
*/
+ @android.ravenwood.annotation.RavenwoodThrow(blockedBy = android.os.ParcelFileDescriptor.class)
public void addOnFileDescriptorEventListener(@NonNull FileDescriptor fd,
@OnFileDescriptorEventListener.Events int events,
@NonNull OnFileDescriptorEventListener listener) {
@@ -221,6 +225,7 @@
* @see OnFileDescriptorEventListener
* @see #addOnFileDescriptorEventListener
*/
+ @android.ravenwood.annotation.RavenwoodThrow(blockedBy = android.os.ParcelFileDescriptor.class)
public void removeOnFileDescriptorEventListener(@NonNull FileDescriptor fd) {
if (fd == null) {
throw new IllegalArgumentException("fd must not be null");
@@ -231,6 +236,7 @@
}
}
+ @android.ravenwood.annotation.RavenwoodThrow(blockedBy = android.os.ParcelFileDescriptor.class)
private void updateOnFileDescriptorEventListenerLocked(FileDescriptor fd, int events,
OnFileDescriptorEventListener listener) {
final int fdNum = fd.getInt$();
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 13572fb..11660f9 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -842,15 +842,19 @@
return "amd64".equals(System.getProperty("os.arch"));
}
- private static SomeArgs sIdentity$ravenwood;
+ private static ThreadLocal<SomeArgs> sIdentity$ravenwood;
/** @hide */
@android.ravenwood.annotation.RavenwoodKeep
- public static void init$ravenwood(int uid, int pid) {
- final SomeArgs args = SomeArgs.obtain();
- args.argi1 = uid;
- args.argi2 = pid;
- sIdentity$ravenwood = args;
+ public static void init$ravenwood(final int uid, final int pid) {
+ sIdentity$ravenwood = ThreadLocal.withInitial(() -> {
+ final SomeArgs args = SomeArgs.obtain();
+ args.argi1 = uid;
+ args.argi2 = pid;
+ args.argi3 = Long.hashCode(Thread.currentThread().getId());
+ args.argi4 = THREAD_PRIORITY_DEFAULT;
+ return args;
+ });
}
/** @hide */
@@ -870,7 +874,7 @@
/** @hide */
public static final int myPid$ravenwood() {
- return Preconditions.requireNonNullViaRavenwoodRule(sIdentity$ravenwood).argi2;
+ return Preconditions.requireNonNullViaRavenwoodRule(sIdentity$ravenwood).get().argi2;
}
/**
@@ -886,10 +890,16 @@
* Returns the identifier of the calling thread, which be used with
* {@link #setThreadPriority(int, int)}.
*/
+ @android.ravenwood.annotation.RavenwoodReplace
public static final int myTid() {
return Os.gettid();
}
+ /** @hide */
+ public static final int myTid$ravenwood() {
+ return Preconditions.requireNonNullViaRavenwoodRule(sIdentity$ravenwood).get().argi3;
+ }
+
/**
* Returns the identifier of this process's uid. This is the kernel uid
* that the process is running under, which is the identity of its
@@ -903,7 +913,7 @@
/** @hide */
public static final int myUid$ravenwood() {
- return Preconditions.requireNonNullViaRavenwoodRule(sIdentity$ravenwood).argi1;
+ return Preconditions.requireNonNullViaRavenwoodRule(sIdentity$ravenwood).get().argi1;
}
/**
@@ -1086,9 +1096,22 @@
* not have permission to modify the given thread, or to use the given
* priority.
*/
+ @android.ravenwood.annotation.RavenwoodReplace
public static final native void setThreadPriority(int tid, int priority)
throws IllegalArgumentException, SecurityException;
+ /** @hide */
+ public static final void setThreadPriority$ravenwood(int tid, int priority) {
+ final SomeArgs args =
+ Preconditions.requireNonNullViaRavenwoodRule(sIdentity$ravenwood).get();
+ if (args.argi3 == tid) {
+ args.argi4 = priority;
+ } else {
+ throw new UnsupportedOperationException(
+ "Cross-thread priority management not yet available in Ravenwood");
+ }
+ }
+
/**
* Call with 'false' to cause future calls to {@link #setThreadPriority(int)} to
* throw an exception if passed a background-level thread priority. This is only
@@ -1226,9 +1249,15 @@
*
* @see #setThreadPriority(int, int)
*/
+ @android.ravenwood.annotation.RavenwoodReplace
public static final native void setThreadPriority(int priority)
throws IllegalArgumentException, SecurityException;
+ /** @hide */
+ public static final void setThreadPriority$ravenwood(int priority) {
+ setThreadPriority(myTid(), priority);
+ }
+
/**
* Return the current priority of a thread, based on Linux priorities.
*
@@ -1242,9 +1271,22 @@
* @throws IllegalArgumentException Throws IllegalArgumentException if
* <var>tid</var> does not exist.
*/
+ @android.ravenwood.annotation.RavenwoodReplace
public static final native int getThreadPriority(int tid)
throws IllegalArgumentException;
+ /** @hide */
+ public static final int getThreadPriority$ravenwood(int tid) {
+ final SomeArgs args =
+ Preconditions.requireNonNullViaRavenwoodRule(sIdentity$ravenwood).get();
+ if (args.argi3 == tid) {
+ return args.argi4;
+ } else {
+ throw new UnsupportedOperationException(
+ "Cross-thread priority management not yet available in Ravenwood");
+ }
+ }
+
/**
* Return the current scheduling policy of a thread, based on Linux.
*
diff --git a/core/java/android/os/SystemClock.java b/core/java/android/os/SystemClock.java
index 49a0bd3..2e6cccb 100644
--- a/core/java/android/os/SystemClock.java
+++ b/core/java/android/os/SystemClock.java
@@ -110,6 +110,11 @@
private static volatile IAlarmManager sIAlarmManager;
/**
+ * Since {@code nanoTime()} is arbitrary, anchor our Ravenwood clocks against it.
+ */
+ private static final long sAnchorNanoTime$ravenwood = System.nanoTime();
+
+ /**
* This class is uninstantiable.
*/
@UnsupportedAppUsage
@@ -193,9 +198,7 @@
/** @hide */
public static long uptimeMillis$ravenwood() {
- // Ravenwood booted in Jan 2023, and has been in deep sleep for one week
- return System.currentTimeMillis() - (1672556400L * 1_000)
- - (DateUtils.WEEK_IN_MILLIS * 1_000);
+ return uptimeNanos() / 1_000_000;
}
/**
@@ -210,9 +213,7 @@
/** @hide */
public static long uptimeNanos$ravenwood() {
- // Ravenwood booted in Jan 2023, and has been in deep sleep for one week
- return System.nanoTime() - (1672556400L * 1_000_000_000)
- - (DateUtils.WEEK_IN_MILLIS * 1_000_000_000);
+ return System.nanoTime() - sAnchorNanoTime$ravenwood;
}
/**
@@ -241,8 +242,7 @@
/** @hide */
public static long elapsedRealtime$ravenwood() {
- // Ravenwood booted in Jan 2023, and has been in deep sleep for one week
- return System.currentTimeMillis() - (1672556400L * 1_000);
+ return elapsedRealtimeNanos() / 1_000_000;
}
/**
@@ -271,8 +271,8 @@
/** @hide */
public static long elapsedRealtimeNanos$ravenwood() {
- // Ravenwood booted in Jan 2023, and has been in deep sleep for one week
- return System.nanoTime() - (1672556400L * 1_000_000_000);
+ // Elapsed realtime is uptime plus an hour that we've been "asleep"
+ return uptimeNanos() + (DateUtils.HOUR_IN_MILLIS * 1_000_000);
}
/**
diff --git a/core/java/android/os/ThreadLocalWorkSource.java b/core/java/android/os/ThreadLocalWorkSource.java
index e9adb20..7c4a2be 100644
--- a/core/java/android/os/ThreadLocalWorkSource.java
+++ b/core/java/android/os/ThreadLocalWorkSource.java
@@ -37,6 +37,7 @@
*
* @hide Only for use within system server.
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public final class ThreadLocalWorkSource {
public static final int UID_NONE = Message.UID_NONE;
private static final ThreadLocal<int []> sWorkSourceUid =
diff --git a/core/java/android/permission/IOnPermissionsChangeListener.aidl b/core/java/android/permission/IOnPermissionsChangeListener.aidl
index afacf1a..c68c0c9 100644
--- a/core/java/android/permission/IOnPermissionsChangeListener.aidl
+++ b/core/java/android/permission/IOnPermissionsChangeListener.aidl
@@ -21,5 +21,5 @@
* {@hide}
*/
oneway interface IOnPermissionsChangeListener {
- void onPermissionsChanged(int uid, String deviceId);
+ void onPermissionsChanged(int uid, String persistentDeviceId);
}
diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java
index 7a158c5..91adc37 100644
--- a/core/java/android/permission/PermissionManager.java
+++ b/core/java/android/permission/PermissionManager.java
@@ -1738,8 +1738,9 @@
}
@Override
- public void onPermissionsChanged(int uid, String deviceId) {
- mHandler.obtainMessage(MSG_PERMISSIONS_CHANGED, uid, 0, deviceId).sendToTarget();
+ public void onPermissionsChanged(int uid, String persistentDeviceId) {
+ mHandler.obtainMessage(MSG_PERMISSIONS_CHANGED, uid, 0, persistentDeviceId)
+ .sendToTarget();
}
@Override
@@ -1747,8 +1748,8 @@
switch (msg.what) {
case MSG_PERMISSIONS_CHANGED: {
final int uid = msg.arg1;
- final String deviceId = msg.obj.toString();
- mListener.onPermissionsChanged(uid, deviceId);
+ final String persistentDeviceId = msg.obj.toString();
+ mListener.onPermissionsChanged(uid, persistentDeviceId);
return true;
}
default:
diff --git a/core/java/android/service/notification/OWNERS b/core/java/android/service/notification/OWNERS
index bb0e6ab..cb0b5fa 100644
--- a/core/java/android/service/notification/OWNERS
+++ b/core/java/android/service/notification/OWNERS
@@ -2,6 +2,7 @@
juliacr@google.com
yurilin@google.com
+matiashe@google.com
jeffdq@google.com
dsandler@android.com
dsandler@google.com
diff --git a/core/java/android/view/inputmethod/ImeTracker.java b/core/java/android/view/inputmethod/ImeTracker.java
index 1bc7353..d4cfd63 100644
--- a/core/java/android/view/inputmethod/ImeTracker.java
+++ b/core/java/android/view/inputmethod/ImeTracker.java
@@ -428,16 +428,25 @@
ImeTracker LOGGER = new ImeTracker() {
{
- // Set logging flag initial value.
- mLogProgress = SystemProperties.getBoolean("persist.debug.imetracker", false);
- // Update logging flag dynamically.
- SystemProperties.addChangeCallback(() ->
- mLogProgress = SystemProperties.getBoolean("persist.debug.imetracker", false));
+ // Read initial system properties.
+ reloadSystemProperties();
+ // Update when system properties change.
+ SystemProperties.addChangeCallback(this::reloadSystemProperties);
}
- /** Whether progress should be logged. */
+ /** Whether {@link #onProgress} calls should be logged. */
private boolean mLogProgress;
+ /** Whether the stack trace at the request call site should be logged. */
+ private boolean mLogStackTrace;
+
+ private void reloadSystemProperties() {
+ mLogProgress = SystemProperties.getBoolean(
+ "persist.debug.imetracker", false);
+ mLogStackTrace = SystemProperties.getBoolean(
+ "persist.debug.imerequest.logstacktrace", false);
+ }
+
@NonNull
@Override
public Token onRequestShow(@Nullable String component, int uid, @Origin int origin,
@@ -447,7 +456,8 @@
reason);
Log.i(TAG, token.mTag + ": onRequestShow at " + Debug.originToString(origin)
- + " reason " + InputMethodDebug.softInputDisplayReasonToString(reason));
+ + " reason " + InputMethodDebug.softInputDisplayReasonToString(reason),
+ mLogStackTrace ? new Throwable() : null);
return token;
}
@@ -461,7 +471,8 @@
reason);
Log.i(TAG, token.mTag + ": onRequestHide at " + Debug.originToString(origin)
- + " reason " + InputMethodDebug.softInputDisplayReasonToString(reason));
+ + " reason " + InputMethodDebug.softInputDisplayReasonToString(reason),
+ mLogStackTrace ? new Throwable() : null);
return token;
}
diff --git a/core/java/android/window/flags/window_surfaces.aconfig b/core/java/android/window/flags/window_surfaces.aconfig
index 11bd22f..0da03fb 100644
--- a/core/java/android/window/flags/window_surfaces.aconfig
+++ b/core/java/android/window/flags/window_surfaces.aconfig
@@ -39,4 +39,12 @@
description: "Remove uses of ScreenCapture#captureDisplay"
is_fixed_read_only: true
bug: "293445881"
-}
\ No newline at end of file
+}
+
+flag {
+ namespace: "window_surfaces"
+ name: "allow_disable_activity_record_input_sink"
+ description: "Whether to allow system activity to disable ActivityRecordInputSink"
+ is_fixed_read_only: true
+ bug: "262477923"
+}
diff --git a/core/java/com/android/internal/display/BrightnessSynchronizer.java b/core/java/com/android/internal/display/BrightnessSynchronizer.java
index d503904..37aaa72 100644
--- a/core/java/com/android/internal/display/BrightnessSynchronizer.java
+++ b/core/java/com/android/internal/display/BrightnessSynchronizer.java
@@ -16,9 +16,14 @@
package com.android.internal.display;
+import static android.Manifest.permission.CONTROL_DISPLAY_BRIGHTNESS;
+
+import android.annotation.RequiresPermission;
+import android.annotation.SuppressLint;
import android.content.ContentResolver;
import android.content.Context;
import android.database.ContentObserver;
+import android.hardware.display.BrightnessInfo;
import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManager.DisplayListener;
import android.net.Uri;
@@ -54,8 +59,7 @@
private static final int MSG_RUN_UPDATE = 1;
// The tolerance within which we consider brightness values approximately equal to eachother.
- // This value is approximately 1/3 of the smallest possible brightness value.
- public static final float EPSILON = 0.001f;
+ public static final float EPSILON = 0.0001f;
private static int sBrightnessUpdateCount = 1;
@@ -70,16 +74,22 @@
private BrightnessUpdate mCurrentUpdate;
private BrightnessUpdate mPendingUpdate;
- public BrightnessSynchronizer(Context context) {
- this(context, Looper.getMainLooper(), SystemClock::uptimeMillis);
+ // Feature flag that will eventually be removed
+ private final boolean mIntRangeUserPerceptionEnabled;
+
+ public BrightnessSynchronizer(Context context, boolean intRangeUserPerceptionEnabled) {
+ this(context, Looper.getMainLooper(), SystemClock::uptimeMillis,
+ intRangeUserPerceptionEnabled);
}
@VisibleForTesting
- public BrightnessSynchronizer(Context context, Looper looper, Clock clock) {
+ public BrightnessSynchronizer(Context context, Looper looper, Clock clock,
+ boolean intRangeUserPerceptionEnabled) {
mContext = context;
mClock = clock;
mBrightnessSyncObserver = new BrightnessSyncObserver();
mHandler = new BrightnessSynchronizerHandler(looper);
+ mIntRangeUserPerceptionEnabled = intRangeUserPerceptionEnabled;
}
/**
@@ -128,6 +138,7 @@
pw.println(" mLatestFloatBrightness=" + mLatestFloatBrightness);
pw.println(" mCurrentUpdate=" + mCurrentUpdate);
pw.println(" mPendingUpdate=" + mPendingUpdate);
+ pw.println(" mIntRangeUserPerceptionEnabled=" + mIntRangeUserPerceptionEnabled);
}
/**
@@ -284,6 +295,78 @@
}
/**
+ * Converts between the int brightness setting and the float brightness system. The int
+ * brightness setting is between 0-255 and matches the brightness slider - e.g. 128 is 50% on
+ * the slider. Accounts for special values such as OFF and invalid values. Accounts for
+ * brightness limits; the maximum value here represents the max value allowed on the slider.
+ */
+ @RequiresPermission(CONTROL_DISPLAY_BRIGHTNESS)
+ public static float brightnessIntSettingToFloat(Context context, int brightnessInt) {
+ if (brightnessInt == PowerManager.BRIGHTNESS_OFF) {
+ return PowerManager.BRIGHTNESS_OFF_FLOAT;
+ } else if (brightnessInt == PowerManager.BRIGHTNESS_INVALID) {
+ return PowerManager.BRIGHTNESS_INVALID_FLOAT;
+ } else {
+ final float minInt = PowerManager.BRIGHTNESS_OFF + 1;
+ final float maxInt = PowerManager.BRIGHTNESS_ON;
+
+ // Normalize to the range [0, 1]
+ float userPerceptionBrightness = MathUtils.norm(minInt, maxInt, brightnessInt);
+
+ // Convert from user-perception to linear scale
+ float linearBrightness = BrightnessUtils.convertGammaToLinear(userPerceptionBrightness);
+
+ // Interpolate to the range [0, currentlyAllowedMax]
+ final Display display = context.getDisplay();
+ if (display == null) {
+ return PowerManager.BRIGHTNESS_INVALID_FLOAT;
+ }
+ final BrightnessInfo info = display.getBrightnessInfo();
+ if (info == null) {
+ return PowerManager.BRIGHTNESS_INVALID_FLOAT;
+ }
+ return MathUtils.lerp(info.brightnessMinimum, info.brightnessMaximum, linearBrightness);
+ }
+ }
+
+ /**
+ * Translates specified value from the float brightness system to the setting int brightness
+ * system. The value returned is between 0-255 and matches the brightness slider - e.g. 128 is
+ * 50% on the slider. Accounts for special values such as OFF and invalid values. Accounts for
+ * brightness limits; the maximum value here represents the max value currently allowed on
+ * the slider.
+ */
+ @RequiresPermission(CONTROL_DISPLAY_BRIGHTNESS)
+ public static int brightnessFloatToIntSetting(Context context, float brightnessFloat) {
+ if (floatEquals(brightnessFloat, PowerManager.BRIGHTNESS_OFF_FLOAT)) {
+ return PowerManager.BRIGHTNESS_OFF;
+ } else if (Float.isNaN(brightnessFloat)) {
+ return PowerManager.BRIGHTNESS_INVALID;
+ } else {
+ // Normalize to the range [0, 1]
+ final Display display = context.getDisplay();
+ if (display == null) {
+ return PowerManager.BRIGHTNESS_INVALID;
+ }
+ final BrightnessInfo info = display.getBrightnessInfo();
+ if (info == null) {
+ return PowerManager.BRIGHTNESS_INVALID;
+ }
+ float linearBrightness =
+ MathUtils.norm(info.brightnessMinimum, info.brightnessMaximum, brightnessFloat);
+
+ // Convert from linear to user-perception scale
+ float userPerceptionBrightness = BrightnessUtils.convertLinearToGamma(linearBrightness);
+
+ // Interpolate to the range [0, 255]
+ final float minInt = PowerManager.BRIGHTNESS_OFF + 1;
+ final float maxInt = PowerManager.BRIGHTNESS_ON;
+ float intBrightness = MathUtils.lerp(minInt, maxInt, userPerceptionBrightness);
+ return Math.round(intBrightness);
+ }
+ }
+
+ /**
* Encapsulates a brightness change event and contains logic for synchronizing the appropriate
* settings for the specified brightness change.
*/
@@ -417,18 +500,28 @@
return mUpdatedTypes != 0x0;
}
+ @SuppressLint("AndroidFrameworkRequiresPermission")
private int getBrightnessAsInt() {
if (mSourceType == TYPE_INT) {
return (int) mBrightness;
}
- return brightnessFloatToInt(mBrightness);
+ if (mIntRangeUserPerceptionEnabled) {
+ return brightnessFloatToIntSetting(mContext, mBrightness);
+ } else {
+ return brightnessFloatToInt(mBrightness);
+ }
}
+ @SuppressLint("AndroidFrameworkRequiresPermission")
private float getBrightnessAsFloat() {
if (mSourceType == TYPE_FLOAT) {
return mBrightness;
}
- return brightnessIntToFloat((int) mBrightness);
+ if (mIntRangeUserPerceptionEnabled) {
+ return brightnessIntSettingToFloat(mContext, (int) mBrightness);
+ } else {
+ return brightnessIntToFloat((int) mBrightness);
+ }
}
private String toStringLabel(int type, float brightness) {
diff --git a/services/core/java/com/android/server/display/BrightnessUtils.java b/core/java/com/android/internal/display/BrightnessUtils.java
similarity index 98%
rename from services/core/java/com/android/server/display/BrightnessUtils.java
rename to core/java/com/android/internal/display/BrightnessUtils.java
index 84fa0cc..6743bab 100644
--- a/services/core/java/com/android/server/display/BrightnessUtils.java
+++ b/core/java/com/android/internal/display/BrightnessUtils.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.display;
+package com.android.internal.display;
import android.util.MathUtils;
diff --git a/core/java/com/android/internal/display/RefreshRateSettingsUtils.java b/core/java/com/android/internal/display/RefreshRateSettingsUtils.java
index e55c641..f5fe12e 100644
--- a/core/java/com/android/internal/display/RefreshRateSettingsUtils.java
+++ b/core/java/com/android/internal/display/RefreshRateSettingsUtils.java
@@ -37,11 +37,22 @@
* @return The highest refresh rate
*/
public static float findHighestRefreshRateForDefaultDisplay(Context context) {
+ return findHighestRefreshRate(context, Display.DEFAULT_DISPLAY);
+ }
+
+ /**
+ * Find the highest refresh rate among all the modes of the specified display.
+ *
+ * @param context The context
+ * @param displayId The display ID
+ * @return The highest refresh rate
+ */
+ public static float findHighestRefreshRate(Context context, int displayId) {
final DisplayManager dm = context.getSystemService(DisplayManager.class);
- final Display display = dm.getDisplay(Display.DEFAULT_DISPLAY);
+ final Display display = dm.getDisplay(displayId);
if (display == null) {
- Log.w(TAG, "No valid default display device");
+ Log.w(TAG, "No valid display device with ID = " + displayId);
return DEFAULT_REFRESH_RATE;
}
diff --git a/core/java/com/android/internal/pm/OWNERS b/core/java/com/android/internal/pm/OWNERS
new file mode 100644
index 0000000..6ef34e2
--- /dev/null
+++ b/core/java/com/android/internal/pm/OWNERS
@@ -0,0 +1,4 @@
+# Bug component: 36137
+
+file:/PACKAGE_MANAGER_OWNERS
+
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 7b075e6..4d208c6 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2301,6 +2301,7 @@
<!-- Allows system apps to call methods to register itself as a mDNS offload engine.
<p>Not for use by third-party or privileged applications.
@SystemApi
+ @FlaggedApi("com.android.net.flags.register_nsd_offload_engine")
@hide This should only be used by system apps.
-->
<permission android:name="android.permission.REGISTER_NSD_OFFLOAD_ENGINE"
diff --git a/graphics/java/android/graphics/Insets.java b/graphics/java/android/graphics/Insets.java
index 1e03c53..2b170b9a 100644
--- a/graphics/java/android/graphics/Insets.java
+++ b/graphics/java/android/graphics/Insets.java
@@ -29,6 +29,7 @@
* Insets are immutable so may be treated as values.
*
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public final class Insets implements Parcelable {
public static final @NonNull Insets NONE = new Insets(0, 0, 0, 0);
diff --git a/graphics/java/android/graphics/Point.java b/graphics/java/android/graphics/Point.java
index 2781ac4b..e5c620b 100644
--- a/graphics/java/android/graphics/Point.java
+++ b/graphics/java/android/graphics/Point.java
@@ -24,6 +24,7 @@
/**
* Point holds two integer coordinates
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public class Point implements Parcelable {
public int x;
public int y;
diff --git a/graphics/java/android/graphics/PointF.java b/graphics/java/android/graphics/PointF.java
index ed9df14..3531785 100644
--- a/graphics/java/android/graphics/PointF.java
+++ b/graphics/java/android/graphics/PointF.java
@@ -23,6 +23,7 @@
/**
* PointF holds two float coordinates
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public class PointF implements Parcelable {
public float x;
public float y;
diff --git a/graphics/java/android/graphics/Rect.java b/graphics/java/android/graphics/Rect.java
index 1a522bd..411a10b 100644
--- a/graphics/java/android/graphics/Rect.java
+++ b/graphics/java/android/graphics/Rect.java
@@ -45,6 +45,7 @@
* into the column and row described by its left and top coordinates, but not
* those of its bottom and right.
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public final class Rect implements Parcelable {
public int left;
public int top;
diff --git a/graphics/java/android/graphics/RectF.java b/graphics/java/android/graphics/RectF.java
index 1d294d5..ff50a0c 100644
--- a/graphics/java/android/graphics/RectF.java
+++ b/graphics/java/android/graphics/RectF.java
@@ -32,6 +32,7 @@
* the rectangle's width and height. Note: most methods do not check to see that
* the coordinates are sorted correctly (i.e. left <= right and top <= bottom).
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public class RectF implements Parcelable {
public float left;
public float top;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
index c7ab6aa..f5b877a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
@@ -963,7 +963,11 @@
&& mTaskView.isAttachedToWindow()) {
// post this to the looper, because if the device orientation just changed, we need to
// let the current shell transition complete before updating the task view bounds.
- post(() -> mTaskView.onLocationChanged());
+ post(() -> {
+ if (mTaskView != null) {
+ mTaskView.onLocationChanged();
+ }
+ });
}
if (mIsOverflow) {
// post this to the looper so that the view has a chance to be laid out before it can
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
index 27dc870..b158f88 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
@@ -250,10 +250,10 @@
SyncTransactionQueue syncQueue,
@ShellMainThread ShellExecutor mainExecutor,
Lazy<Transitions> transitionsLazy,
- DockStateReader dockStateReader,
- CompatUIConfiguration compatUIConfiguration,
- CompatUIShellCommandHandler compatUIShellCommandHandler,
- AccessibilityManager accessibilityManager) {
+ Lazy<DockStateReader> dockStateReader,
+ Lazy<CompatUIConfiguration> compatUIConfiguration,
+ Lazy<CompatUIShellCommandHandler> compatUIShellCommandHandler,
+ Lazy<AccessibilityManager> accessibilityManager) {
if (!context.getResources().getBoolean(R.bool.config_enableCompatUIController)) {
return Optional.empty();
}
@@ -268,10 +268,10 @@
syncQueue,
mainExecutor,
transitionsLazy,
- dockStateReader,
- compatUIConfiguration,
- compatUIShellCommandHandler,
- accessibilityManager));
+ dockStateReader.get(),
+ compatUIConfiguration.get(),
+ compatUIShellCommandHandler.get(),
+ accessibilityManager.get()));
}
@WMSingleton
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/HomeTransitionObserver.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/HomeTransitionObserver.java
index b528089d15..5c02dbc 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/HomeTransitionObserver.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/HomeTransitionObserver.java
@@ -17,6 +17,7 @@
package com.android.wm.shell.transition;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static android.window.TransitionInfo.FLAG_BACK_GESTURE_ANIMATED;
import static com.android.wm.shell.transition.Transitions.TransitionObserver;
@@ -61,9 +62,10 @@
}
final int mode = change.getMode();
+ final boolean isBackGesture = change.hasFlags(FLAG_BACK_GESTURE_ANIMATED);
if (taskInfo.getActivityType() == ACTIVITY_TYPE_HOME
- && TransitionUtil.isOpenOrCloseMode(mode)) {
- notifyHomeVisibilityChanged(TransitionUtil.isOpeningType(mode));
+ && (TransitionUtil.isOpenOrCloseMode(mode) || isBackGesture)) {
+ notifyHomeVisibilityChanged(TransitionUtil.isOpeningType(mode) || isBackGesture);
}
}
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandlerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandlerTest.kt
index a5629c8..b355ab0 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandlerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandlerTest.kt
@@ -14,8 +14,6 @@
import android.window.TransitionInfo
import android.window.TransitionInfo.FLAG_IS_WALLPAPER
import androidx.test.filters.SmallTest
-import com.android.server.testutils.any
-import com.android.server.testutils.mock
import com.android.wm.shell.RootTaskDisplayAreaOrganizer
import com.android.wm.shell.ShellTestCase
import com.android.wm.shell.TestRunningTaskInfoBuilder
@@ -28,8 +26,10 @@
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
+import org.mockito.kotlin.mock
import org.mockito.kotlin.never
import org.mockito.kotlin.verify
import org.mockito.kotlin.verifyZeroInteractions
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/HomeTransitionObserverTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/HomeTransitionObserverTest.java
index ea7c0d9..421c445 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/HomeTransitionObserverTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/HomeTransitionObserverTest.java
@@ -18,8 +18,10 @@
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_TO_BACK;
+import static android.window.TransitionInfo.FLAG_BACK_GESTURE_ANIMATED;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
@@ -145,6 +147,26 @@
verify(mListener, times(0)).onHomeVisibilityChanged(anyBoolean());
}
+ @Test
+ public void testHomeActivityWithBackGestureNotifiesHomeIsVisible() throws RemoteException {
+ TransitionInfo info = mock(TransitionInfo.class);
+ TransitionInfo.Change change = mock(TransitionInfo.Change.class);
+ ActivityManager.RunningTaskInfo taskInfo = mock(ActivityManager.RunningTaskInfo.class);
+ when(change.getTaskInfo()).thenReturn(taskInfo);
+ when(info.getChanges()).thenReturn(new ArrayList<>(List.of(change)));
+
+ when(change.hasFlags(FLAG_BACK_GESTURE_ANIMATED)).thenReturn(true);
+ setupTransitionInfo(taskInfo, change, ACTIVITY_TYPE_HOME, TRANSIT_CHANGE);
+
+ mHomeTransitionObserver.onTransitionReady(mock(IBinder.class),
+ info,
+ mock(SurfaceControl.Transaction.class),
+ mock(SurfaceControl.Transaction.class));
+
+ verify(mListener, times(1)).onHomeVisibilityChanged(true);
+ }
+
+
/**
* Helper class to initialize variables for the rest.
*/
diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp
index d056248..8748dab 100644
--- a/libs/androidfw/AssetManager2.cpp
+++ b/libs/androidfw/AssetManager2.cpp
@@ -603,7 +603,7 @@
std::unique_ptr<Asset> asset = assets->GetAssetsProvider()->Open(filename, mode);
if (asset) {
if (out_cookie != nullptr) {
- *out_cookie = i;
+ *out_cookie = i - 1;
}
return asset;
}
diff --git a/libs/hwui/hwui/Typeface.cpp b/libs/hwui/hwui/Typeface.cpp
index b63ee1b..a9d1a2a 100644
--- a/libs/hwui/hwui/Typeface.cpp
+++ b/libs/hwui/hwui/Typeface.cpp
@@ -25,8 +25,9 @@
#include "MinikinSkia.h"
#include "SkPaint.h"
-#include "SkStream.h" // Fot tests.
+#include "SkStream.h" // For tests.
#include "SkTypeface.h"
+#include "utils/TypefaceUtils.h"
#include <minikin/FontCollection.h>
#include <minikin/FontFamily.h>
@@ -186,7 +187,9 @@
LOG_ALWAYS_FATAL_IF(fstat(fd, &st) == -1, "Failed to stat file %s", kRobotoFont);
void* data = mmap(nullptr, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
std::unique_ptr<SkStreamAsset> fontData(new SkMemoryStream(data, st.st_size));
- sk_sp<SkTypeface> typeface = SkTypeface::MakeFromStream(std::move(fontData));
+ sk_sp<SkFontMgr> fm = android::FreeTypeFontMgr();
+ LOG_ALWAYS_FATAL_IF(fm == nullptr, "Could not load FreeType SkFontMgr");
+ sk_sp<SkTypeface> typeface = fm->makeFromStream(std::move(fontData));
LOG_ALWAYS_FATAL_IF(typeface == nullptr, "Failed to make typeface from %s", kRobotoFont);
std::shared_ptr<minikin::MinikinFont> font =
diff --git a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
index 2b2e399..ffa915a 100644
--- a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
+++ b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
@@ -56,6 +56,7 @@
int nestLevel) const {
LOG_ALWAYS_FATAL_IF(0 == nestLevel && !displayList.mProjectionReceiver);
for (auto& child : displayList.mChildNodes) {
+ if (!child.getRenderNode()->isRenderable()) continue;
const RenderProperties& childProperties = child.getNodeProperties();
// immediate children cannot be projected on their parent
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index de842e6..9f63dfd 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -1065,17 +1065,8 @@
* @see #isVolumeFixed()
*/
public void adjustVolume(int direction, @PublicVolumeFlags int flags) {
- if (autoPublicVolumeApiHardening()) {
- final IAudioService service = getService();
- try {
- service.adjustVolume(direction, flags);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- } else {
- MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext());
- helper.sendAdjustVolumeBy(USE_DEFAULT_STREAM_TYPE, direction, flags);
- }
+ MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext());
+ helper.sendAdjustVolumeBy(USE_DEFAULT_STREAM_TYPE, direction, flags);
}
/**
@@ -1104,17 +1095,8 @@
*/
public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType,
@PublicVolumeFlags int flags) {
- if (autoPublicVolumeApiHardening()) {
- final IAudioService service = getService();
- try {
- service.adjustSuggestedStreamVolume(direction, suggestedStreamType, flags);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- } else {
- MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext());
- helper.sendAdjustVolumeBy(suggestedStreamType, direction, flags);
- }
+ MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext());
+ helper.sendAdjustVolumeBy(suggestedStreamType, direction, flags);
}
/** @hide */
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index 11e3a08..b4ca485 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -500,10 +500,6 @@
in String packageName, int uid, int pid, in UserHandle userHandle,
int targetSdkVersion);
- oneway void adjustVolume(int direction, int flags);
-
- oneway void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags);
-
boolean isMusicActive(in boolean remotely);
int getDeviceMaskForStream(in int streamType);
diff --git a/packages/InputDevices/res/raw/keyboard_layout_english_uk.kcm b/packages/InputDevices/res/raw/keyboard_layout_english_uk.kcm
index 93a5082..071f9f4 100644
--- a/packages/InputDevices/res/raw/keyboard_layout_english_uk.kcm
+++ b/packages/InputDevices/res/raw/keyboard_layout_english_uk.kcm
@@ -116,6 +116,9 @@
base: 'w'
shift, capslock: 'W'
shift+capslock: 'w'
+ ralt: '\u1e83'
+ shift+ralt, capslock+ralt: '\u1e82'
+ shift+capslock+ralt: '\u1e83'
}
key E {
@@ -147,6 +150,9 @@
base: 'y'
shift, capslock: 'Y'
shift+capslock: 'y'
+ ralt: '\u00fd'
+ shift+ralt, capslock+ralt: '\u00dd'
+ shift+capslock+ralt: '\u00fd'
}
key U {
@@ -313,6 +319,9 @@
base: 'c'
shift, capslock: 'C'
shift+capslock: 'c'
+ ralt: '\u00e7'
+ shift+ralt, capslock+ralt: '\u00c7'
+ shift+capslock+ralt: '\u00e7'
}
key V {
diff --git a/packages/InputDevices/res/raw/keyboard_layout_french.kcm b/packages/InputDevices/res/raw/keyboard_layout_french.kcm
index 4906304..636f98d 100644
--- a/packages/InputDevices/res/raw/keyboard_layout_french.kcm
+++ b/packages/InputDevices/res/raw/keyboard_layout_french.kcm
@@ -44,7 +44,7 @@
label: '2'
base: '\u00e9'
shift: '2'
- ralt: '~'
+ ralt: '\u0303'
}
key 3 {
@@ -79,7 +79,7 @@
label: '7'
base: '\u00e8'
shift: '7'
- ralt: '`'
+ ralt: '\u0300'
}
key 8 {
diff --git a/packages/InputDevices/res/xml/keyboard_layouts.xml b/packages/InputDevices/res/xml/keyboard_layouts.xml
index 7f23f74..ee49b23 100644
--- a/packages/InputDevices/res/xml/keyboard_layouts.xml
+++ b/packages/InputDevices/res/xml/keyboard_layouts.xml
@@ -94,7 +94,7 @@
android:name="keyboard_layout_swiss_german"
android:label="@string/keyboard_layout_swiss_german_label"
android:keyboardLayout="@raw/keyboard_layout_swiss_german"
- android:keyboardLocale="de-Latn-CH"
+ android:keyboardLocale="de-Latn-CH|gsw-Latn-CH"
android:keyboardLayoutType="qwertz" />
<keyboard-layout
diff --git a/packages/PackageInstaller/AndroidManifest.xml b/packages/PackageInstaller/AndroidManifest.xml
index 6e47689..0d1c9b0 100644
--- a/packages/PackageInstaller/AndroidManifest.xml
+++ b/packages/PackageInstaller/AndroidManifest.xml
@@ -181,6 +181,18 @@
<receiver android:name="androidx.profileinstaller.ProfileInstallReceiver"
tools:node="remove" />
+
+ <activity android:name=".UnarchiveActivity"
+ android:configChanges="orientation|keyboardHidden|screenSize"
+ android:theme="@style/Theme.AlertDialogActivity.NoActionBar"
+ android:excludeFromRecents="true"
+ android:noHistory="true"
+ android:exported="true">
+ <intent-filter android:priority="1">
+ <action android:name="android.intent.action.UNARCHIVE_DIALOG" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity>
</application>
</manifest>
diff --git a/packages/PackageInstaller/res/values/strings.xml b/packages/PackageInstaller/res/values/strings.xml
index 4eaa39b..0a2e880 100644
--- a/packages/PackageInstaller/res/values/strings.xml
+++ b/packages/PackageInstaller/res/values/strings.xml
@@ -257,4 +257,14 @@
<!-- Notification shown in status bar when an application is successfully installed.
[CHAR LIMIT=50] -->
<string name="notification_installation_success_status">Successfully installed \u201c<xliff:g id="appname" example="Package Installer">%1$s</xliff:g>\u201d</string>
+
+ <!-- The title of a dialog which asks the user to restore (i.e. re-install, re-download) an app
+ after parts of the app have been previously moved into the cloud for temporary storage.
+ "installername" is the app that will facilitate the download of the app. [CHAR LIMIT=50] -->
+ <string name="unarchive_application_title">Restore <xliff:g id="appname" example="Bird Game">%1$s</xliff:g> from <xliff:g id="installername" example="App Store">%1$s</xliff:g>?</string>
+ <!-- After the user confirms the dialog, a download will start. [CHAR LIMIT=none] -->
+ <string name="unarchive_body_text">This app will begin to download in the background</string>
+ <!-- The action to restore (i.e. re-install, re-download) an app after parts of the app have been previously moved
+ into the cloud for temporary storage. [CHAR LIMIT=15] -->
+ <string name="restore">Restore</string>
</resources>
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/UnarchiveActivity.java b/packages/PackageInstaller/src/com/android/packageinstaller/UnarchiveActivity.java
new file mode 100644
index 0000000..754437e
--- /dev/null
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/UnarchiveActivity.java
@@ -0,0 +1,151 @@
+/*
+ * 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.packageinstaller;
+
+import static android.Manifest.permission;
+import static android.content.pm.PackageManager.GET_PERMISSIONS;
+import static android.content.pm.PackageManager.MATCH_ARCHIVED_PACKAGES;
+
+import android.app.Activity;
+import android.app.DialogFragment;
+import android.app.Fragment;
+import android.app.FragmentTransaction;
+import android.content.IntentSender;
+import android.content.pm.PackageInstaller;
+import android.content.pm.PackageManager;
+import android.os.Bundle;
+import android.os.Process;
+import android.util.Log;
+
+import androidx.annotation.Nullable;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Objects;
+
+public class UnarchiveActivity extends Activity {
+
+ public static final String EXTRA_UNARCHIVE_INTENT_SENDER =
+ "android.content.pm.extra.UNARCHIVE_INTENT_SENDER";
+ static final String APP_TITLE = "com.android.packageinstaller.unarchive.app_title";
+ static final String INSTALLER_TITLE = "com.android.packageinstaller.unarchive.installer_title";
+
+ private static final String TAG = "UnarchiveActivity";
+
+ private String mPackageName;
+ private IntentSender mIntentSender;
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(null);
+
+ int callingUid = getLaunchedFromUid();
+ if (callingUid == Process.INVALID_UID) {
+ // Cannot reach Package/ActivityManager. Aborting uninstall.
+ Log.e(TAG, "Could not determine the launching uid.");
+
+ setResult(Activity.RESULT_FIRST_USER);
+ finish();
+ return;
+ }
+
+ String callingPackage = getPackageNameForUid(callingUid);
+ if (callingPackage == null) {
+ Log.e(TAG, "Package not found for originating uid " + callingUid);
+ setResult(Activity.RESULT_FIRST_USER);
+ finish();
+ return;
+ }
+
+ // We don't check the AppOpsManager here for REQUEST_INSTALL_PACKAGES because the requester
+ // is not the source of the installation.
+ boolean hasRequestInstallPermission = Arrays.asList(getRequestedPermissions(callingPackage))
+ .contains(permission.REQUEST_INSTALL_PACKAGES);
+ boolean hasInstallPermission = getBaseContext().checkPermission(permission.INSTALL_PACKAGES,
+ 0 /* random value for pid */, callingUid) != PackageManager.PERMISSION_GRANTED;
+ if (!hasRequestInstallPermission && !hasInstallPermission) {
+ Log.e(TAG, "Uid " + callingUid + " does not have "
+ + permission.REQUEST_INSTALL_PACKAGES + " or "
+ + permission.INSTALL_PACKAGES);
+ setResult(Activity.RESULT_FIRST_USER);
+ finish();
+ return;
+ }
+
+ Bundle extras = getIntent().getExtras();
+ mPackageName = extras.getString(PackageInstaller.EXTRA_PACKAGE_NAME);
+ mIntentSender = extras.getParcelable(EXTRA_UNARCHIVE_INTENT_SENDER, IntentSender.class);
+ Objects.requireNonNull(mPackageName);
+ Objects.requireNonNull(mIntentSender);
+
+ PackageManager pm = getPackageManager();
+ try {
+ String appTitle = pm.getApplicationInfo(mPackageName,
+ PackageManager.ApplicationInfoFlags.of(
+ MATCH_ARCHIVED_PACKAGES)).loadLabel(pm).toString();
+ // TODO(ag/25387215) Get the real installer title here after fixing getInstallSource for
+ // archived apps.
+ showDialogFragment(appTitle, "installerTitle");
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.e(TAG, "Invalid packageName: " + e.getMessage());
+ }
+ }
+
+ @Nullable
+ private String[] getRequestedPermissions(String callingPackage) {
+ String[] requestedPermissions = null;
+ try {
+ requestedPermissions = getPackageManager()
+ .getPackageInfo(callingPackage, GET_PERMISSIONS).requestedPermissions;
+ } catch (PackageManager.NameNotFoundException e) {
+ // Should be unreachable because we've just fetched the packageName above.
+ Log.e(TAG, "Package not found for " + callingPackage);
+ }
+ return requestedPermissions;
+ }
+
+ void startUnarchive() {
+ try {
+ getPackageManager().getPackageInstaller().requestUnarchive(mPackageName, mIntentSender);
+ } catch (PackageManager.NameNotFoundException | IOException e) {
+ Log.e(TAG, "RequestUnarchive failed with %s." + e.getMessage());
+ }
+ }
+
+ private void showDialogFragment(String appTitle, String installerAppTitle) {
+ FragmentTransaction ft = getFragmentManager().beginTransaction();
+ Fragment prev = getFragmentManager().findFragmentByTag("dialog");
+ if (prev != null) {
+ ft.remove(prev);
+ }
+
+ Bundle args = new Bundle();
+ args.putString(APP_TITLE, appTitle);
+ args.putString(INSTALLER_TITLE, installerAppTitle);
+ DialogFragment fragment = new UnarchiveFragment();
+ fragment.setArguments(args);
+ fragment.show(ft, "dialog");
+ }
+
+ private String getPackageNameForUid(int sourceUid) {
+ String[] packagesForUid = getPackageManager().getPackagesForUid(sourceUid);
+ if (packagesForUid == null) {
+ return null;
+ }
+ return packagesForUid[0];
+ }
+}
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/UnarchiveFragment.java b/packages/PackageInstaller/src/com/android/packageinstaller/UnarchiveFragment.java
new file mode 100644
index 0000000..6ccbc4c
--- /dev/null
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/UnarchiveFragment.java
@@ -0,0 +1,59 @@
+/*
+ * 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.packageinstaller;
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.content.DialogInterface;
+import android.os.Bundle;
+
+public class UnarchiveFragment extends DialogFragment implements
+ DialogInterface.OnClickListener {
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ String appTitle = getArguments().getString(UnarchiveActivity.APP_TITLE);
+
+ AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(getActivity());
+
+ dialogBuilder.setTitle(
+ String.format(getContext().getString(R.string.unarchive_application_title),
+ appTitle));
+ dialogBuilder.setMessage(R.string.unarchive_body_text);
+
+ dialogBuilder.setPositiveButton(R.string.restore, this);
+ dialogBuilder.setNegativeButton(android.R.string.cancel, this);
+
+ return dialogBuilder.create();
+ }
+
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ if (which == Dialog.BUTTON_POSITIVE) {
+ ((UnarchiveActivity) getActivity()).startUnarchive();
+ }
+ }
+
+ @Override
+ public void onDismiss(DialogInterface dialog) {
+ super.onDismiss(dialog);
+ if (isAdded()) {
+ getActivity().finish();
+ }
+ }
+}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/OnBackEffect.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/OnBackEffect.kt
new file mode 100644
index 0000000..3991f26
--- /dev/null
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/OnBackEffect.kt
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.spa.framework.compose
+
+import androidx.activity.OnBackPressedCallback
+import androidx.activity.OnBackPressedDispatcher
+import androidx.activity.compose.LocalOnBackPressedDispatcherOwner
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.DisposableEffect
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.rememberUpdatedState
+import androidx.compose.ui.platform.LocalLifecycleOwner
+
+/**
+ * An effect for detecting presses of the system back button, and the back event will not be
+ * consumed by this effect.
+ *
+ * Calling this in your composable adds the given lambda to the [OnBackPressedDispatcher] of the
+ * [LocalOnBackPressedDispatcherOwner].
+ *
+ * @param onBack the action invoked by pressing the system back
+ */
+@Composable
+fun OnBackEffect(onBack: () -> Unit) {
+ val backDispatcher = checkNotNull(LocalOnBackPressedDispatcherOwner.current) {
+ "No OnBackPressedDispatcherOwner was provided via LocalOnBackPressedDispatcherOwner"
+ }.onBackPressedDispatcher
+
+ // Safely update the current `onBack` lambda when a new one is provided
+ val currentOnBack by rememberUpdatedState(onBack)
+ // Remember in Composition a back callback that calls the `onBack` lambda
+ val backCallback = remember {
+ object : OnBackPressedCallback(true) {
+ override fun handleOnBackPressed() {
+ remove()
+ currentOnBack()
+ backDispatcher.onBackPressed()
+ }
+ }
+ }
+ val lifecycleOwner = LocalLifecycleOwner.current
+ DisposableEffect(lifecycleOwner, backDispatcher) {
+ // Add callback to the backDispatcher
+ backDispatcher.addCallback(lifecycleOwner, backCallback)
+ // When the effect leaves the Composition, remove the callback
+ onDispose {
+ backCallback.remove()
+ }
+ }
+}
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/compose/OnBackEffectTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/compose/OnBackEffectTest.kt
new file mode 100644
index 0000000..5881686
--- /dev/null
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/compose/OnBackEffectTest.kt
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.spa.framework.compose
+
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.ui.test.hasText
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.navigation.compose.NavHost
+import androidx.navigation.compose.composable
+import androidx.navigation.compose.rememberNavController
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.settingslib.spa.testutils.waitUntilExists
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.delay
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class OnBackEffectTest {
+ @get:Rule
+ val composeTestRule = createComposeRule()
+
+ private var onBackEffectCalled = false
+
+ @Test
+ fun onBackEffect() {
+ composeTestRule.setContent {
+ TestNavHost {
+ val navController = LocalNavController.current
+ LaunchedEffect(Unit) {
+ navController.navigate(ROUTE_B)
+ delay(100)
+ navController.navigateBack()
+ }
+ }
+ }
+
+ composeTestRule.waitUntilExists(hasText(ROUTE_A))
+ assertThat(onBackEffectCalled).isTrue()
+ }
+
+ @Composable
+ private fun TestNavHost(content: @Composable () -> Unit) {
+ val navController = rememberNavController()
+ CompositionLocalProvider(navController.localNavController()) {
+ NavHost(navController, ROUTE_A) {
+ composable(route = ROUTE_A) { Text(ROUTE_A) }
+ composable(route = ROUTE_B) {
+ Text(ROUTE_B)
+
+ OnBackEffect {
+ onBackEffectCalled = true
+ }
+ }
+ }
+ content()
+ }
+ }
+
+ private companion object {
+ const val ROUTE_A = "RouteA"
+ const val ROUTE_B = "RouteB"
+ }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/VolumeControlProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/VolumeControlProfile.java
index f83e37b..3774b88 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/VolumeControlProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/VolumeControlProfile.java
@@ -37,9 +37,7 @@
import java.util.List;
import java.util.concurrent.Executor;
-/**
- * VolumeControlProfile handles Bluetooth Volume Control Controller role
- */
+/** VolumeControlProfile handles Bluetooth Volume Control Controller role */
public class VolumeControlProfile implements LocalBluetoothProfile {
private static final String TAG = "VolumeControlProfile";
private static boolean DEBUG = true;
@@ -77,8 +75,8 @@
}
device = mDeviceManager.addDevice(nextDevice);
}
- device.onProfileStateChanged(VolumeControlProfile.this,
- BluetoothProfile.STATE_CONNECTED);
+ device.onProfileStateChanged(
+ VolumeControlProfile.this, BluetoothProfile.STATE_CONNECTED);
device.refresh();
}
@@ -95,32 +93,36 @@
}
}
- VolumeControlProfile(Context context, CachedBluetoothDeviceManager deviceManager,
+ VolumeControlProfile(
+ Context context,
+ CachedBluetoothDeviceManager deviceManager,
LocalBluetoothProfileManager profileManager) {
mContext = context;
mDeviceManager = deviceManager;
mProfileManager = profileManager;
- BluetoothAdapter.getDefaultAdapter().getProfileProxy(context,
- new VolumeControlProfile.VolumeControlProfileServiceListener(),
- BluetoothProfile.VOLUME_CONTROL);
+ BluetoothAdapter.getDefaultAdapter()
+ .getProfileProxy(
+ context,
+ new VolumeControlProfile.VolumeControlProfileServiceListener(),
+ BluetoothProfile.VOLUME_CONTROL);
}
-
/**
- * Registers a {@link BluetoothVolumeControl.Callback} that will be invoked during the
- * operation of this profile.
+ * Registers a {@link BluetoothVolumeControl.Callback} that will be invoked during the operation
+ * of this profile.
*
- * Repeated registration of the same <var>callback</var> object will have no effect after
- * the first call to this method, even when the <var>executor</var> is different. API caller
- * would have to call {@link #unregisterCallback(BluetoothVolumeControl.Callback)} with
- * the same callback object before registering it again.
+ * <p>Repeated registration of the same <var>callback</var> object will have no effect after the
+ * first call to this method, even when the <var>executor</var> is different. API caller would
+ * have to call {@link #unregisterCallback(BluetoothVolumeControl.Callback)} with the same
+ * callback object before registering it again.
*
* @param executor an {@link Executor} to execute given callback
* @param callback user implementation of the {@link BluetoothVolumeControl.Callback}
* @throws IllegalArgumentException if a null executor or callback is given
*/
- public void registerCallback(@NonNull @CallbackExecutor Executor executor,
+ public void registerCallback(
+ @NonNull @CallbackExecutor Executor executor,
@NonNull BluetoothVolumeControl.Callback callback) {
if (mService == null) {
Log.w(TAG, "Proxy not attached to service. Cannot register callback.");
@@ -131,8 +133,9 @@
/**
* Unregisters the specified {@link BluetoothVolumeControl.Callback}.
- * <p>The same {@link BluetoothVolumeControl.Callback} object used when calling
- * {@link #registerCallback(Executor, BluetoothVolumeControl.Callback)} must be used.
+ *
+ * <p>The same {@link BluetoothVolumeControl.Callback} object used when calling {@link
+ * #registerCallback(Executor, BluetoothVolumeControl.Callback)} must be used.
*
* <p>Callbacks are automatically unregistered when application process goes away
*
@@ -153,8 +156,8 @@
* @param device {@link BluetoothDevice} representing the remote device
* @param volumeOffset volume offset to be set on the remote device
*/
- public void setVolumeOffset(BluetoothDevice device,
- @IntRange(from = -255, to = 255) int volumeOffset) {
+ public void setVolumeOffset(
+ BluetoothDevice device, @IntRange(from = -255, to = 255) int volumeOffset) {
if (mService == null) {
Log.w(TAG, "Proxy not attached to service. Cannot set volume offset.");
return;
@@ -165,16 +168,13 @@
}
mService.setVolumeOffset(device, volumeOffset);
}
-
/**
- * Provides information about the possibility to set volume offset on the remote device.
- * If the remote device supports Volume Offset Control Service, it is automatically
- * connected.
+ * Provides information about the possibility to set volume offset on the remote device. If the
+ * remote device supports Volume Offset Control Service, it is automatically connected.
*
* @param device {@link BluetoothDevice} representing the remote device
* @return {@code true} if volume offset function is supported and available to use on the
- * remote device. When Bluetooth is off, the return value should always be
- * {@code false}.
+ * remote device. When Bluetooth is off, the return value should always be {@code false}.
*/
public boolean isVolumeOffsetAvailable(BluetoothDevice device) {
if (mService == null) {
@@ -188,6 +188,28 @@
return mService.isVolumeOffsetAvailable(device);
}
+ /**
+ * Tells the remote device to set a volume.
+ *
+ * @param device {@link BluetoothDevice} representing the remote device
+ * @param volume volume to be set on the remote device
+ * @param isGroupOp whether to set the volume to remote devices within the same CSIP group
+ */
+ public void setDeviceVolume(
+ BluetoothDevice device,
+ @IntRange(from = 0, to = 255) int volume,
+ boolean isGroupOp) {
+ if (mService == null) {
+ Log.w(TAG, "Proxy not attached to service. Cannot set volume offset.");
+ return;
+ }
+ if (device == null) {
+ Log.w(TAG, "Device is null. Cannot set volume offset.");
+ return;
+ }
+ mService.setDeviceVolume(device, volume, isGroupOp);
+ }
+
@Override
public boolean accessProfileEnabled() {
return false;
@@ -199,10 +221,9 @@
}
/**
- * Gets VolumeControlProfile devices matching connection states{
- * {@code BluetoothProfile.STATE_CONNECTED},
- * {@code BluetoothProfile.STATE_CONNECTING},
- * {@code BluetoothProfile.STATE_DISCONNECTING}}
+ * Gets VolumeControlProfile devices matching connection states{ {@code
+ * BluetoothProfile.STATE_CONNECTED}, {@code BluetoothProfile.STATE_CONNECTING}, {@code
+ * BluetoothProfile.STATE_DISCONNECTING}}
*
* @return Matching device list
*/
@@ -211,8 +232,11 @@
return new ArrayList<BluetoothDevice>(0);
}
return mService.getDevicesMatchingConnectionStates(
- new int[]{BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_CONNECTING,
- BluetoothProfile.STATE_DISCONNECTING});
+ new int[] {
+ BluetoothProfile.STATE_CONNECTED,
+ BluetoothProfile.STATE_CONNECTING,
+ BluetoothProfile.STATE_DISCONNECTING
+ });
}
@Override
@@ -285,7 +309,7 @@
@Override
public int getSummaryResourceForDevice(BluetoothDevice device) {
- return 0; // VCP profile not displayed in UI
+ return 0; // VCP profile not displayed in UI
}
@Override
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/VolumeControlProfileTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/VolumeControlProfileTest.java
index c560627..fe1529d 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/VolumeControlProfileTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/VolumeControlProfileTest.java
@@ -54,18 +54,14 @@
public class VolumeControlProfileTest {
private static final int TEST_VOLUME_OFFSET = 10;
+ private static final int TEST_VOLUME_VALUE = 10;
- @Rule
- public final MockitoRule mockito = MockitoJUnit.rule();
+ @Rule public final MockitoRule mockito = MockitoJUnit.rule();
- @Mock
- private CachedBluetoothDeviceManager mDeviceManager;
- @Mock
- private LocalBluetoothProfileManager mProfileManager;
- @Mock
- private BluetoothDevice mBluetoothDevice;
- @Mock
- private BluetoothVolumeControl mService;
+ @Mock private CachedBluetoothDeviceManager mDeviceManager;
+ @Mock private LocalBluetoothProfileManager mProfileManager;
+ @Mock private BluetoothDevice mBluetoothDevice;
+ @Mock private BluetoothVolumeControl mService;
private final Context mContext = ApplicationProvider.getApplicationContext();
private BluetoothProfile.ServiceListener mServiceListener;
@@ -177,14 +173,14 @@
@Test
public void getConnectedDevices_returnCorrectList() {
mServiceListener.onServiceConnected(BluetoothProfile.VOLUME_CONTROL, mService);
- int[] connectedStates = new int[] {
- BluetoothProfile.STATE_CONNECTED,
- BluetoothProfile.STATE_CONNECTING,
- BluetoothProfile.STATE_DISCONNECTING};
- List<BluetoothDevice> connectedList = Arrays.asList(
- mBluetoothDevice,
- mBluetoothDevice,
- mBluetoothDevice);
+ int[] connectedStates =
+ new int[] {
+ BluetoothProfile.STATE_CONNECTED,
+ BluetoothProfile.STATE_CONNECTING,
+ BluetoothProfile.STATE_DISCONNECTING
+ };
+ List<BluetoothDevice> connectedList =
+ Arrays.asList(mBluetoothDevice, mBluetoothDevice, mBluetoothDevice);
when(mService.getDevicesMatchingConnectionStates(connectedStates))
.thenReturn(connectedList);
@@ -222,6 +218,16 @@
}
@Test
+ public void setDeviceVolume_verifyIsCalled() {
+ mServiceListener.onServiceConnected(BluetoothProfile.VOLUME_CONTROL, mService);
+
+ mProfile.setDeviceVolume(mBluetoothDevice, TEST_VOLUME_VALUE, /* isGroupOp= */ true);
+
+ verify(mService)
+ .setDeviceVolume(mBluetoothDevice, TEST_VOLUME_VALUE, /* isGroupOp= */ true);
+ }
+
+ @Test
public void isVolumeOffsetAvailable_verifyIsCalledAndReturnTrue() {
mServiceListener.onServiceConnected(BluetoothProfile.VOLUME_CONTROL, mService);
when(mService.isVolumeOffsetAvailable(mBluetoothDevice)).thenReturn(true);
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java
index f0e3c99..6434209 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java
@@ -133,16 +133,6 @@
boolean afterKeyguardGone,
boolean deferred);
- /** Execute a runnable after dismissing keyguard. */
- void executeRunnableDismissingKeyguard(
- Runnable runnable,
- Runnable cancelAction,
- boolean dismissShade,
- boolean afterKeyguardGone,
- boolean deferred,
- boolean willAnimateOnKeyguard,
- @Nullable String customMessage);
-
/** Whether we should animate an activity launch. */
boolean shouldAnimateLaunch(boolean isActivityIntent);
diff --git a/packages/SystemUI/res-keyguard/layout/shade_carrier_new.xml b/packages/SystemUI/res-keyguard/layout/shade_carrier_new.xml
index 952f056..cc99f5e 100644
--- a/packages/SystemUI/res-keyguard/layout/shade_carrier_new.xml
+++ b/packages/SystemUI/res-keyguard/layout/shade_carrier_new.xml
@@ -22,13 +22,15 @@
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center_vertical"
- android:orientation="horizontal" >
+ android:orientation="horizontal"
+ android:theme="@style/Theme.SystemUI.QuickSettings.Header" >
<com.android.systemui.util.AutoMarqueeTextView
android:id="@+id/mobile_carrier_text"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
+ android:textAppearance="@style/TextAppearance.QS.Status.Carriers"
android:layout_marginEnd="@dimen/qs_carrier_margin_width"
android:visibility="gone"
android:textDirection="locale"
diff --git a/packages/SystemUI/res/drawable/notification_material_bg.xml b/packages/SystemUI/res/drawable/notification_material_bg.xml
index 355e75d..9c08f5e 100644
--- a/packages/SystemUI/res/drawable/notification_material_bg.xml
+++ b/packages/SystemUI/res/drawable/notification_material_bg.xml
@@ -18,7 +18,7 @@
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:color="?android:attr/colorControlHighlight">
- <item>
+ <item android:id="@+id/notification_background_color_layer">
<shape>
<solid android:color="?androidprv:attr/materialColorSurfaceContainerHigh" />
</shape>
diff --git a/packages/SystemUI/src/com/android/keyguard/ActiveUnlockConfig.kt b/packages/SystemUI/src/com/android/keyguard/ActiveUnlockConfig.kt
index 3757274..1ee58de 100644
--- a/packages/SystemUI/src/com/android/keyguard/ActiveUnlockConfig.kt
+++ b/packages/SystemUI/src/com/android/keyguard/ActiveUnlockConfig.kt
@@ -317,7 +317,7 @@
}
keyguardUpdateMonitor?.let {
- val anyFaceEnrolled = it.isFaceEnrolled
+ val anyFaceEnrolled = it.isFaceEnabledAndEnrolled
val anyFingerprintEnrolled = it.isUnlockWithFingerprintPossible(
selectedUserInteractor.getSelectedUserId())
val udfpsEnrolled = it.isUdfpsEnrolled
@@ -372,7 +372,7 @@
keyguardUpdateMonitor?.let {
pw.println(" shouldRequestActiveUnlockOnUnlockIntentFromBiometricEnrollment=" +
"${shouldRequestActiveUnlockOnUnlockIntentFromBiometricEnrollment()}")
- pw.println(" faceEnrolled=${it.isFaceEnrolled}")
+ pw.println(" isFaceEnabledAndEnrolled=${it.isFaceEnabledAndEnrolled}")
pw.println(" fpUnlockPossible=${
it.isUnlockWithFingerprintPossible(selectedUserInteractor.getSelectedUserId())}")
pw.println(" udfpsEnrolled=${it.isUdfpsEnrolled}")
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardFaceListenModel.kt b/packages/SystemUI/src/com/android/keyguard/KeyguardFaceListenModel.kt
deleted file mode 100644
index d7019b5..0000000
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardFaceListenModel.kt
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.keyguard
-
-import android.annotation.CurrentTimeMillisLong
-import com.android.systemui.common.buffer.RingBuffer
-import com.android.systemui.dump.DumpsysTableLogger
-import com.android.systemui.dump.Row
-
-/** Verbose debug information associated. */
-data class KeyguardFaceListenModel(
- @CurrentTimeMillisLong override var timeMillis: Long = 0L,
- override var userId: Int = 0,
- override var listening: Boolean = false,
- // keep sorted
- var allowedDisplayStateWhileAwake: Boolean = false,
- var alternateBouncerShowing: Boolean = false,
- var authInterruptActive: Boolean = false,
- var biometricSettingEnabledForUser: Boolean = false,
- var bouncerFullyShown: Boolean = false,
- var faceAndFpNotAuthenticated: Boolean = false,
- var faceAuthAllowed: Boolean = false,
- var faceDisabled: Boolean = false,
- var faceLockedOut: Boolean = false,
- var goingToSleep: Boolean = false,
- var keyguardAwake: Boolean = false,
- var keyguardGoingAway: Boolean = false,
- var listeningForFaceAssistant: Boolean = false,
- var occludingAppRequestingFaceAuth: Boolean = false,
- var postureAllowsListening: Boolean = false,
- var secureCameraLaunched: Boolean = false,
- var supportsDetect: Boolean = false,
- var switchingUser: Boolean = false,
- var systemUser: Boolean = false,
- var udfpsFingerDown: Boolean = false,
- var userNotTrustedOrDetectionIsNeeded: Boolean = false,
-) : KeyguardListenModel() {
-
- /** List of [String] to be used as a [Row] with [DumpsysTableLogger]. */
- val asStringList: List<String> by lazy {
- listOf(
- DATE_FORMAT.format(timeMillis),
- timeMillis.toString(),
- userId.toString(),
- listening.toString(),
- // keep sorted
- allowedDisplayStateWhileAwake.toString(),
- alternateBouncerShowing.toString(),
- authInterruptActive.toString(),
- biometricSettingEnabledForUser.toString(),
- bouncerFullyShown.toString(),
- faceAndFpNotAuthenticated.toString(),
- faceAuthAllowed.toString(),
- faceDisabled.toString(),
- faceLockedOut.toString(),
- goingToSleep.toString(),
- keyguardAwake.toString(),
- keyguardGoingAway.toString(),
- listeningForFaceAssistant.toString(),
- occludingAppRequestingFaceAuth.toString(),
- postureAllowsListening.toString(),
- secureCameraLaunched.toString(),
- supportsDetect.toString(),
- switchingUser.toString(),
- systemUser.toString(),
- udfpsFingerDown.toString(),
- userNotTrustedOrDetectionIsNeeded.toString(),
- )
- }
-
- /**
- * [RingBuffer] to store [KeyguardFaceListenModel]. After the buffer is full, it will recycle
- * old events.
- *
- * Do not use [append] to add new elements. Instead use [insert], as it will recycle if
- * necessary.
- */
- class Buffer {
- private val buffer = RingBuffer(CAPACITY) { KeyguardFaceListenModel() }
-
- fun insert(model: KeyguardFaceListenModel) {
- buffer.advance().apply {
- timeMillis = model.timeMillis
- userId = model.userId
- listening = model.listening
- // keep sorted
- allowedDisplayStateWhileAwake = model.allowedDisplayStateWhileAwake
- alternateBouncerShowing = model.alternateBouncerShowing
- authInterruptActive = model.authInterruptActive
- biometricSettingEnabledForUser = model.biometricSettingEnabledForUser
- bouncerFullyShown = model.bouncerFullyShown
- faceAndFpNotAuthenticated = model.faceAndFpNotAuthenticated
- faceAuthAllowed = model.faceAuthAllowed
- faceDisabled = model.faceDisabled
- faceLockedOut = model.faceLockedOut
- goingToSleep = model.goingToSleep
- keyguardAwake = model.keyguardAwake
- keyguardGoingAway = model.keyguardGoingAway
- listeningForFaceAssistant = model.listeningForFaceAssistant
- occludingAppRequestingFaceAuth = model.occludingAppRequestingFaceAuth
- postureAllowsListening = model.postureAllowsListening
- secureCameraLaunched = model.secureCameraLaunched
- supportsDetect = model.supportsDetect
- switchingUser = model.switchingUser
- systemUser = model.systemUser
- udfpsFingerDown = model.udfpsFingerDown
- userNotTrustedOrDetectionIsNeeded = model.userNotTrustedOrDetectionIsNeeded
- }
- }
- /**
- * Returns the content of the buffer (sorted from latest to newest).
- *
- * @see KeyguardFingerprintListenModel.asStringList
- */
- fun toList(): List<Row> {
- return buffer.asSequence().map { it.asStringList }.toList()
- }
- }
-
- companion object {
- const val CAPACITY = 40 // number of logs to retain
-
- /** Headers for dumping a table using [DumpsysTableLogger]. */
- @JvmField
- val TABLE_HEADERS =
- listOf(
- "timestamp",
- "time_millis",
- "userId",
- "listening",
- // keep sorted
- "allowedDisplayStateWhileAwake",
- "alternateBouncerShowing",
- "authInterruptActive",
- "biometricSettingEnabledForUser",
- "bouncerFullyShown",
- "faceAndFpNotAuthenticated",
- "faceAuthAllowed",
- "faceDisabled",
- "faceLockedOut",
- "goingToSleep",
- "keyguardAwake",
- "keyguardGoingAway",
- "listeningForFaceAssistant",
- "occludingAppRequestingFaceAuth",
- "postureAllowsListening",
- "secureCameraLaunched",
- "supportsDetect",
- "switchingUser",
- "systemUser",
- "udfpsFingerDown",
- "userNotTrustedOrDetectionIsNeeded",
- )
- }
-}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
index 1b6112f..f706301 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
@@ -214,7 +214,6 @@
public void onUserInput() {
mBouncerMessageInteractor.onPrimaryBouncerUserInput();
mKeyguardFaceAuthInteractor.onPrimaryBouncerUserInput();
- mUpdateMonitor.cancelFaceAuth();
}
@Override
@@ -340,16 +339,11 @@
private final SwipeListener mSwipeListener = new SwipeListener() {
@Override
public void onSwipeUp() {
- if (!mUpdateMonitor.isFaceDetectionRunning()) {
- mKeyguardFaceAuthInteractor.onSwipeUpOnBouncer();
- boolean didFaceAuthRun = mUpdateMonitor.requestFaceAuth(
- FaceAuthApiRequestReason.SWIPE_UP_ON_BOUNCER);
+ if (mKeyguardFaceAuthInteractor.canFaceAuthRun()) {
mKeyguardSecurityCallback.userActivity();
- if (didFaceAuthRun) {
- showMessage(/* message= */ null, /* colorState= */ null, /* animated= */ true);
- }
}
- if (mUpdateMonitor.isFaceEnrolled()) {
+ mKeyguardFaceAuthInteractor.onSwipeUpOnBouncer();
+ if (mKeyguardFaceAuthInteractor.isFaceAuthEnabledAndEnrolled()) {
mUpdateMonitor.requestActiveUnlock(
ActiveUnlockConfig.ActiveUnlockRequestOrigin.UNLOCK_INTENT,
"swipeUpOnBouncer");
@@ -755,7 +749,7 @@
}
mView.onResume(
mSecurityModel.getSecurityMode(mSelectedUserInteractor.getSelectedUserId()),
- mKeyguardStateController.isFaceEnrolled());
+ mKeyguardStateController.isFaceEnrolledAndEnabled());
}
/** Sets an initial message that would override the default message */
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index baab637..c5bb099 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -34,48 +34,11 @@
import static android.hardware.biometrics.BiometricSourceType.FINGERPRINT;
import static android.os.BatteryManager.BATTERY_STATUS_UNKNOWN;
import static android.os.BatteryManager.CHARGING_POLICY_DEFAULT;
-import static android.os.PowerManager.WAKE_REASON_UNKNOWN;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN;
-import static com.android.keyguard.FaceAuthReasonKt.apiRequestReasonToUiEvent;
-import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_DISPLAY_OFF;
-import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_NON_STRONG_BIOMETRIC_ALLOWED_CHANGED;
-import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_STOPPED_DREAM_STARTED;
-import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_STOPPED_FACE_CANCEL_NOT_RECEIVED;
-import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_STOPPED_FINISHED_GOING_TO_SLEEP;
-import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_STOPPED_FP_LOCKED_OUT;
-import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_STOPPED_KEYGUARD_GOING_AWAY;
-import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_STOPPED_TRUST_ENABLED;
-import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_STOPPED_USER_INPUT_ON_BOUNCER;
-import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_TRIGGERED_ALL_AUTHENTICATORS_REGISTERED;
-import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_TRIGGERED_ALTERNATE_BIOMETRIC_BOUNCER_SHOWN;
-import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_TRIGGERED_DURING_CANCELLATION;
-import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_TRIGGERED_ENROLLMENTS_CHANGED;
-import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_TRIGGERED_FACE_LOCKOUT_RESET;
-import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_TRIGGERED_OCCLUDING_APP_REQUESTED;
-import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_TRIGGERED_ON_REACH_GESTURE_ON_AOD;
-import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_TRIGGERED_RETRY_AFTER_HW_UNAVAILABLE;
-import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_TRIGGERED_TRUST_DISABLED;
-import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_UPDATED_ASSISTANT_VISIBILITY_CHANGED;
-import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_UPDATED_BIOMETRIC_ENABLED_ON_KEYGUARD;
-import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_UPDATED_CAMERA_LAUNCHED;
-import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_UPDATED_FP_AUTHENTICATED;
-import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_UPDATED_GOING_TO_SLEEP;
-import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_UPDATED_KEYGUARD_OCCLUSION_CHANGED;
-import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_UPDATED_KEYGUARD_RESET;
-import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_UPDATED_KEYGUARD_VISIBILITY_CHANGED;
-import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_UPDATED_ON_FACE_AUTHENTICATED;
-import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_UPDATED_ON_KEYGUARD_INIT;
-import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_UPDATED_POSTURE_CHANGED;
-import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_UPDATED_PRIMARY_BOUNCER_SHOWN;
-import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_UPDATED_STARTED_WAKING_UP;
-import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_UPDATED_STRONG_AUTH_CHANGED;
-import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_UPDATED_USER_SWITCHING;
-import static com.android.systemui.DejankUtils.whitelistIpcs;
-import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_AWAKE;
import static com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_OPENED;
import static com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_UNKNOWN;
@@ -104,10 +67,7 @@
import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback;
import android.hardware.biometrics.SensorProperties;
import android.hardware.biometrics.SensorPropertiesInternal;
-import android.hardware.face.FaceAuthenticateOptions;
import android.hardware.face.FaceManager;
-import android.hardware.face.FaceSensorPropertiesInternal;
-import android.hardware.face.IFaceAuthenticatorsRegisteredCallback;
import android.hardware.fingerprint.FingerprintAuthenticateOptions;
import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.FingerprintManager.AuthenticationCallback;
@@ -137,7 +97,6 @@
import android.text.TextUtils;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
-import android.view.Display;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -161,7 +120,6 @@
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.dump.DumpsysTableLogger;
-import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.keyguard.domain.interactor.FaceAuthenticationListener;
import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor;
import com.android.systemui.keyguard.shared.constants.TrustAgentUiEvent;
@@ -172,12 +130,10 @@
import com.android.systemui.keyguard.shared.model.FailedFaceAuthenticationStatus;
import com.android.systemui.keyguard.shared.model.HelpFaceAuthenticationStatus;
import com.android.systemui.keyguard.shared.model.SuccessFaceAuthenticationStatus;
-import com.android.systemui.keyguard.shared.model.SysUiFaceAuthenticateOptions;
import com.android.systemui.log.SessionTracker;
import com.android.systemui.plugins.WeatherData;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.res.R;
-import com.android.systemui.settings.DisplayTracker;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.shared.system.TaskStackChangeListeners;
@@ -318,7 +274,6 @@
private final boolean mIsSystemUser;
private final AuthController mAuthController;
private final UiEventLogger mUiEventLogger;
- private final Set<Integer> mFaceAcquiredInfoIgnoreList;
private final Set<String> mAllowFingerprintOnOccludingActivitiesFromPackage;
private final PackageManager mPackageManager;
private int mStatusBarState;
@@ -339,26 +294,6 @@
}
}
};
- private final DisplayTracker.Callback mDisplayCallback = new DisplayTracker.Callback() {
- @Override
- public void onDisplayChanged(int displayId) {
- if (displayId != Display.DEFAULT_DISPLAY) {
- return;
- }
-
- if (mWakefulness.getWakefulness() == WAKEFULNESS_AWAKE
- && mDisplayTracker.getDisplay(mDisplayTracker.getDefaultDisplayId()).getState()
- == Display.STATE_OFF) {
- mAllowedDisplayStateWhileAwakeForFaceAuth = false;
- updateFaceListeningState(
- BIOMETRIC_ACTION_STOP,
- FACE_AUTH_DISPLAY_OFF
- );
- } else {
- mAllowedDisplayStateWhileAwakeForFaceAuth = true;
- }
- }
- };
private final FaceWakeUpTriggersConfig mFaceWakeUpTriggersConfig;
HashMap<Integer, SimData> mSimDatas = new HashMap<>();
@@ -377,9 +312,7 @@
private boolean mNeedsSlowUnlockTransition;
private boolean mAssistantVisible;
private boolean mOccludingAppRequestingFp;
- private boolean mOccludingAppRequestingFace;
private boolean mSecureCameraLaunched;
- private boolean mAllowedDisplayStateWhileAwakeForFaceAuth = true;
private boolean mBiometricPromptShowing;
@VisibleForTesting
protected boolean mTelephonyCapable;
@@ -409,7 +342,6 @@
private final TrustManager mTrustManager;
private final UserManager mUserManager;
private final DevicePolicyManager mDevicePolicyManager;
- private final DevicePostureController mPostureController;
private final BroadcastDispatcher mBroadcastDispatcher;
private final InteractionJankMonitor mInteractionJankMonitor;
private final LatencyTracker mLatencyTracker;
@@ -422,13 +354,9 @@
@Nullable
private final FingerprintManager mFpm;
@Nullable
- private final FaceManager mFaceManager;
- @Nullable
private KeyguardFaceAuthInteractor mFaceAuthInteractor;
private final TaskStackChangeListeners mTaskStackChangeListeners;
private final IActivityTaskManager mActivityTaskManager;
- private final WakefulnessLifecycle mWakefulness;
- private final DisplayTracker mDisplayTracker;
private final SelectedUserInteractor mSelectedUserInteractor;
private final LockPatternUtils mLockPatternUtils;
@VisibleForTesting
@@ -439,11 +367,9 @@
private List<SubscriptionInfo> mSubscriptionInfo;
@VisibleForTesting
protected int mFingerprintRunningState = BIOMETRIC_STATE_STOPPED;
- private int mFaceRunningState = BIOMETRIC_STATE_STOPPED;
private boolean mIsDreaming;
private boolean mLogoutEnabled;
private int mActiveMobileDataSubscription = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
- private int mPostureState = DEVICE_POSTURE_UNKNOWN;
private FingerprintInteractiveToAuthProvider mFingerprintInteractiveToAuthProvider;
/**
@@ -455,7 +381,6 @@
// If the HAL dies or is unable to authenticate, keyguard should retry after a short delay
private int mHardwareFingerprintUnavailableRetryCount = 0;
- private int mHardwareFaceUnavailableRetryCount = 0;
private static final int HAL_ERROR_RETRY_TIMEOUT = 500; // ms
private static final int HAL_ERROR_RETRY_MAX = 20;
@@ -465,7 +390,6 @@
@VisibleForTesting
protected final Runnable mFpCancelNotReceived = this::onFingerprintCancelNotReceived;
- private final Runnable mFaceCancelNotReceived = this::onFaceCancelNotReceived;
private final Provider<SessionTracker> mSessionTrackerProvider;
@VisibleForTesting
@@ -481,8 +405,7 @@
public void onChanged(boolean enabled, int userId) {
mHandler.post(() -> {
mBiometricEnabledForUser.put(userId, enabled);
- updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE,
- FACE_AUTH_UPDATED_BIOMETRIC_ENABLED_ON_KEYGUARD);
+ updateFingerprintListeningState(BIOMETRIC_ACTION_UPDATE);
});
}
};
@@ -525,15 +448,11 @@
private final KeyguardFingerprintListenModel.Buffer mFingerprintListenBuffer =
new KeyguardFingerprintListenModel.Buffer();
- private final KeyguardFaceListenModel.Buffer mFaceListenBuffer =
- new KeyguardFaceListenModel.Buffer();
private final KeyguardActiveUnlockModel.Buffer mActiveUnlockTriggerBuffer =
new KeyguardActiveUnlockModel.Buffer();
@VisibleForTesting
SparseArray<BiometricAuthenticated> mUserFingerprintAuthenticated = new SparseArray<>();
- @VisibleForTesting
- SparseArray<BiometricAuthenticated> mUserFaceAuthenticated = new SparseArray<>();
private static int sCurrentUser;
@@ -561,11 +480,9 @@
// authenticating. TrustManager sends an onTrustChanged whenever a user unlocks keyguard,
// for this reason we need to make sure to not authenticate.
if (wasTrusted == enabled || enabled) {
- updateBiometricListeningState(BIOMETRIC_ACTION_STOP,
- FACE_AUTH_STOPPED_TRUST_ENABLED);
+ updateFingerprintListeningState(BIOMETRIC_ACTION_STOP);
} else {
- updateBiometricListeningState(BIOMETRIC_ACTION_START,
- FACE_AUTH_TRIGGERED_TRUST_DISABLED);
+ updateFingerprintListeningState(BIOMETRIC_ACTION_START);
}
mLogger.logTrustChanged(wasTrusted, enabled, userId);
@@ -807,8 +724,6 @@
public void setKeyguardGoingAway(boolean goingAway) {
mKeyguardGoingAway = goingAway;
if (mKeyguardGoingAway) {
- updateFaceListeningState(BIOMETRIC_ACTION_STOP,
- FACE_AUTH_STOPPED_KEYGUARD_GOING_AWAY);
for (int i = 0; i < mCallbacks.size(); i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
@@ -855,29 +770,12 @@
}
}
- if (occlusionChanged) {
- updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE,
- FACE_AUTH_UPDATED_KEYGUARD_OCCLUSION_CHANGED);
- } else if (showingChanged) {
- updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE,
- FACE_AUTH_UPDATED_KEYGUARD_VISIBILITY_CHANGED);
+ if (occlusionChanged || showingChanged) {
+ updateFingerprintListeningState(BIOMETRIC_ACTION_UPDATE);
}
}
/**
- * Request to listen for face authentication when an app is occluding keyguard.
- *
- * @param request if true and mKeyguardOccluded, request face auth listening, else default
- * to normal behavior.
- * See {@link KeyguardUpdateMonitor#shouldListenForFace()}
- */
- public void requestFaceAuthOnOccludingApp(boolean request) {
- mOccludingAppRequestingFace = request;
- int action = mOccludingAppRequestingFace ? BIOMETRIC_ACTION_UPDATE : BIOMETRIC_ACTION_STOP;
- updateFaceListeningState(action, FACE_AUTH_TRIGGERED_OCCLUDING_APP_REQUESTED);
- }
-
- /**
* Request to listen for fingerprint when an app is occluding keyguard.
*
* @param request if true and mKeyguardOccluded, request fingerprint listening, else default
@@ -894,8 +792,7 @@
*/
public void onCameraLaunched() {
mSecureCameraLaunched = true;
- updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE,
- FACE_AUTH_UPDATED_CAMERA_LAUNCHED);
+ updateFingerprintListeningState(BIOMETRIC_ACTION_UPDATE);
}
/**
@@ -951,8 +848,7 @@
// Don't send cancel if authentication succeeds
mFingerprintCancelSignal = null;
mLogger.logFingerprintSuccess(userId, isStrongBiometric);
- updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE,
- FACE_AUTH_UPDATED_FP_AUTHENTICATED);
+ updateFingerprintListeningState(BIOMETRIC_ACTION_UPDATE);
for (int i = 0; i < mCallbacks.size(); i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
@@ -1025,7 +921,6 @@
mLogger.logFingerprintDetected(authUserId, isStrongBiometric);
} else if (biometricSourceType == FACE) {
mLogger.logFaceDetected(authUserId, isStrongBiometric);
- setFaceRunningState(BIOMETRIC_STATE_STOPPED);
}
Trace.endSection();
@@ -1140,7 +1035,6 @@
if (isUdfpsEnrolled()) {
updateFingerprintListeningState(BIOMETRIC_ACTION_UPDATE);
}
- stopListeningForFace(FACE_AUTH_STOPPED_FP_LOCKED_OUT);
}
mLogger.logFingerprintError(msgId, errString);
@@ -1218,16 +1112,11 @@
public void onFaceAuthenticated(int userId, boolean isStrongBiometric) {
Trace.beginSection("KeyGuardUpdateMonitor#onFaceAuthenticated");
Assert.isMainThread();
- mUserFaceAuthenticated.put(userId,
- new BiometricAuthenticated(true, isStrongBiometric));
// Update/refresh trust state only if user can skip bouncer
if (getUserCanSkipBouncer(userId)) {
mTrustManager.unlockedByBiometricForUser(userId, FACE);
}
- // Don't send cancel if authentication succeeds
- mFaceCancelSignal = null;
- updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE,
- FACE_AUTH_UPDATED_ON_FACE_AUTHENTICATED);
+ updateFingerprintListeningState(BIOMETRIC_ACTION_UPDATE);
mLogger.d("onFaceAuthenticated");
for (int i = 0; i < mCallbacks.size(); i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
@@ -1247,11 +1136,6 @@
Trace.endSection();
}
- /**
- * @deprecated This is being migrated to use modern architecture, this method is visible purely
- * for bridging the gap while the migration is active.
- */
- @Deprecated
private void handleFaceAuthFailed() {
Assert.isMainThread();
String reason =
@@ -1264,8 +1148,6 @@
"faceFailure-" + reason);
mLogger.d("onFaceAuthFailed");
- mFaceCancelSignal = null;
- setFaceRunningState(BIOMETRIC_STATE_STOPPED);
for (int i = 0; i < mCallbacks.size(); i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
@@ -1276,11 +1158,6 @@
mContext.getString(R.string.kg_face_not_recognized));
}
- /**
- * @deprecated This is being migrated to use modern architecture, this method is visible purely
- * for bridging the gap while the migration is active.
- */
- @Deprecated
private void handleFaceAcquired(int acquireInfo) {
Assert.isMainThread();
for (int i = 0; i < mCallbacks.size(); i++) {
@@ -1298,44 +1175,23 @@
}
}
- /**
- * @deprecated This is being migrated to use modern architecture, this method is visible purely
- * for bridging the gap while the migration is active.
- */
- @Deprecated
private void handleFaceAuthenticated(int authUserId, boolean isStrongBiometric) {
Trace.beginSection("KeyGuardUpdateMonitor#handlerFaceAuthenticated");
- try {
- if (mGoingToSleep) {
- mLogger.d("Aborted successful auth because device is going to sleep.");
- return;
- }
- final int userId = mSelectedUserInteractor.getSelectedUserId(true);
- if (userId != authUserId) {
- mLogger.logFaceAuthForWrongUser(authUserId);
- return;
- }
- if (!isFaceAuthInteractorEnabled() && isFaceDisabled(userId)) {
- mLogger.logFaceAuthDisabledForUser(userId);
- return;
- }
- mLogger.logFaceAuthSuccess(userId);
- onFaceAuthenticated(userId, isStrongBiometric);
- } finally {
- setFaceRunningState(BIOMETRIC_STATE_STOPPED);
+ if (mGoingToSleep) {
+ mLogger.d("Aborted successful auth because device is going to sleep.");
+ return;
}
+ final int userId = mSelectedUserInteractor.getSelectedUserId(true);
+ if (userId != authUserId) {
+ mLogger.logFaceAuthForWrongUser(authUserId);
+ return;
+ }
+ mLogger.logFaceAuthSuccess(userId);
+ onFaceAuthenticated(userId, isStrongBiometric);
Trace.endSection();
}
- /**
- * @deprecated This is being migrated to use modern architecture, this method is visible purely
- * for bridging the gap while the migration is active.
- */
- @Deprecated
private void handleFaceHelp(int msgId, String helpString) {
- if (mFaceAcquiredInfoIgnoreList.contains(msgId)) {
- return;
- }
Assert.isMainThread();
for (int i = 0; i < mCallbacks.size(); i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
@@ -1345,49 +1201,19 @@
}
}
- /**
- * @deprecated This is being migrated to use modern architecture, this method is visible purely
- * for bridging the gap while the migration is active.
- */
- @Deprecated
private void handleFaceError(int msgId, final String originalErrMsg) {
Assert.isMainThread();
String errString = originalErrMsg;
mLogger.logFaceAuthError(msgId, originalErrMsg);
- if (mHandler.hasCallbacks(mFaceCancelNotReceived)) {
- mHandler.removeCallbacks(mFaceCancelNotReceived);
- }
// Error is always the end of authentication lifecycle
- mFaceCancelSignal = null;
boolean cameraPrivacyEnabled = mSensorPrivacyManager.isSensorPrivacyEnabled(
SensorPrivacyManager.TOGGLE_TYPE_SOFTWARE, SensorPrivacyManager.Sensors.CAMERA);
- if (msgId == FaceManager.FACE_ERROR_CANCELED
- && mFaceRunningState == BIOMETRIC_STATE_CANCELLING_RESTARTING) {
- setFaceRunningState(BIOMETRIC_STATE_STOPPED);
- updateFaceListeningState(BIOMETRIC_ACTION_UPDATE,
- FACE_AUTH_TRIGGERED_DURING_CANCELLATION);
- } else {
- setFaceRunningState(BIOMETRIC_STATE_STOPPED);
- }
-
final boolean isHwUnavailable = msgId == FaceManager.FACE_ERROR_HW_UNAVAILABLE;
- if (isHwUnavailable
- || msgId == FaceManager.FACE_ERROR_UNABLE_TO_PROCESS) {
- if (mHardwareFaceUnavailableRetryCount < HAL_ERROR_RETRY_MAX) {
- mHardwareFaceUnavailableRetryCount++;
- mHandler.removeCallbacks(mRetryFaceAuthentication);
- mHandler.postDelayed(mRetryFaceAuthentication, HAL_ERROR_RETRY_TIMEOUT);
- }
- }
-
- boolean lockedOutStateChanged = false;
if (msgId == FaceManager.FACE_ERROR_LOCKOUT_PERMANENT) {
- lockedOutStateChanged = !mFaceLockedOutPermanent;
- mFaceLockedOutPermanent = true;
- if (isFaceClass3()) {
+ if (getFaceAuthInteractor() != null && getFaceAuthInteractor().isFaceAuthStrong()) {
updateFingerprintListeningState(BIOMETRIC_ACTION_STOP);
}
}
@@ -1404,10 +1230,6 @@
}
}
- if (lockedOutStateChanged) {
- notifyLockedOutStateChanged(FACE);
- }
-
if (mActiveUnlockConfig.shouldRequestActiveUnlockOnFaceError(msgId)) {
requestActiveUnlock(
ActiveUnlockConfig.ActiveUnlockRequestOrigin.BIOMETRIC_FAIL,
@@ -1415,49 +1237,6 @@
}
}
- private final Runnable mRetryFaceAuthentication = new Runnable() {
- @Override
- public void run() {
- mLogger.logRetryingAfterFaceHwUnavailable(mHardwareFaceUnavailableRetryCount);
- updateFaceListeningState(BIOMETRIC_ACTION_UPDATE,
- FACE_AUTH_TRIGGERED_RETRY_AFTER_HW_UNAVAILABLE);
- }
- };
-
- private void onFaceCancelNotReceived() {
- mLogger.e("Face cancellation not received, transitioning to STOPPED");
- mFaceRunningState = BIOMETRIC_STATE_STOPPED;
- KeyguardUpdateMonitor.this.updateFaceListeningState(BIOMETRIC_ACTION_STOP,
- FACE_AUTH_STOPPED_FACE_CANCEL_NOT_RECEIVED);
- }
-
- private void handleFaceLockoutReset(@LockoutMode int mode) {
- mLogger.logFaceLockoutReset(mode);
- final boolean wasLockoutPermanent = mFaceLockedOutPermanent;
- mFaceLockedOutPermanent = (mode == BIOMETRIC_LOCKOUT_PERMANENT);
- final boolean changed = (mFaceLockedOutPermanent != wasLockoutPermanent);
-
- mHandler.postDelayed(() -> updateFaceListeningState(BIOMETRIC_ACTION_UPDATE,
- FACE_AUTH_TRIGGERED_FACE_LOCKOUT_RESET), getBiometricLockoutDelay());
-
- if (changed) {
- notifyLockedOutStateChanged(FACE);
- }
- }
-
- private void setFaceRunningState(int faceRunningState) {
- boolean wasRunning = mFaceRunningState == BIOMETRIC_STATE_RUNNING;
- boolean isRunning = faceRunningState == BIOMETRIC_STATE_RUNNING;
- mFaceRunningState = faceRunningState;
- mLogger.logFaceRunningState(mFaceRunningState);
- // Clients of KeyguardUpdateMonitor don't care about the internal state or about the
- // asynchronousness of the cancel cycle. So only notify them if the actually running state
- // has changed.
- if (wasRunning != isRunning) {
- notifyFaceRunningStateChanged();
- }
- }
-
private void notifyFaceRunningStateChanged() {
Assert.isMainThread();
for (int i = 0; i < mCallbacks.size(); i++) {
@@ -1478,14 +1257,7 @@
*/
@Deprecated
public boolean isFaceDetectionRunning() {
- if (isFaceAuthInteractorEnabled()) {
- return getFaceAuthInteractor().isRunning();
- }
- return mFaceRunningState == BIOMETRIC_STATE_RUNNING;
- }
-
- private boolean isFaceAuthInteractorEnabled() {
- return mFaceAuthInteractor != null && mFaceAuthInteractor.isEnabled();
+ return getFaceAuthInteractor() != null && getFaceAuthInteractor().isRunning();
}
private @Nullable KeyguardFaceAuthInteractor getFaceAuthInteractor() {
@@ -1495,14 +1267,32 @@
/**
* Set the face auth interactor that should be used for initiating face authentication.
*/
- public void setFaceAuthInteractor(@Nullable KeyguardFaceAuthInteractor faceAuthInteractor) {
+ public void setFaceAuthInteractor(KeyguardFaceAuthInteractor faceAuthInteractor) {
+ if (mFaceAuthInteractor != null) {
+ mFaceAuthInteractor.unregisterListener(mFaceAuthenticationListener);
+ }
mFaceAuthInteractor = faceAuthInteractor;
mFaceAuthInteractor.registerListener(mFaceAuthenticationListener);
}
- private FaceAuthenticationListener mFaceAuthenticationListener =
+ private final FaceAuthenticationListener mFaceAuthenticationListener =
new FaceAuthenticationListener() {
@Override
+ public void onAuthEnrollmentStateChanged(boolean enrolled) {
+ notifyAboutEnrollmentChange(TYPE_FACE);
+ }
+
+ @Override
+ public void onRunningStateChanged(boolean isRunning) {
+ notifyFaceRunningStateChanged();
+ }
+
+ @Override
+ public void onLockoutStateChanged(boolean isLockedOut) {
+ notifyLockedOutStateChanged(FACE);
+ }
+
+ @Override
public void onAuthenticationStatusChanged(
@NonNull FaceAuthenticationStatus status
) {
@@ -1546,32 +1336,14 @@
}
/**
- * @deprecated This method is not needed anymore with the new face auth system.
- */
- @Deprecated
- private boolean isFaceDisabled(int userId) {
- // TODO(b/140035044)
- return whitelistIpcs(() ->
- (mDevicePolicyManager.getKeyguardDisabledFeatures(null, userId)
- & DevicePolicyManager.KEYGUARD_DISABLE_FACE) != 0
- || isSimPinSecure());
- }
-
- /**
* @return whether the current user has been authenticated with face. This may be true
* on the lockscreen if the user doesn't have bypass enabled.
*
- * @deprecated This is being migrated to use modern architecture.
+ * @deprecated Use {@link KeyguardFaceAuthInteractor#isAuthenticated()}
*/
@Deprecated
public boolean getIsFaceAuthenticated() {
- boolean faceAuthenticated = false;
- BiometricAuthenticated bioFaceAuthenticated =
- mUserFaceAuthenticated.get(mSelectedUserInteractor.getSelectedUserId());
- if (bioFaceAuthenticated != null) {
- faceAuthenticated = bioFaceAuthenticated.mAuthenticated;
- }
- return faceAuthenticated;
+ return getFaceAuthInteractor() != null && getFaceAuthInteractor().isAuthenticated();
}
public boolean getUserCanSkipBouncer(int userId) {
@@ -1590,17 +1362,19 @@
BiometricAuthenticated fingerprint = mUserFingerprintAuthenticated.get(userId);
boolean fingerprintAllowed = fingerprint != null && fingerprint.mAuthenticated
&& isUnlockingWithBiometricAllowed(fingerprint.mIsStrongBiometric);
- return fingerprintAllowed || getUserUnlockedWithFace(userId);
+ boolean unlockedByFace = isCurrentUserUnlockedWithFace() && isUnlockingWithBiometricAllowed(
+ FACE);
+ return fingerprintAllowed || unlockedByFace;
}
/**
* Returns whether the user is unlocked with face.
+ * @deprecated Use {@link KeyguardFaceAuthInteractor#isAuthenticated()} instead
*/
- public boolean getUserUnlockedWithFace(int userId) {
- BiometricAuthenticated face = mUserFaceAuthenticated.get(userId);
- return face != null && face.mAuthenticated
- && isUnlockingWithBiometricAllowed(face.mIsStrongBiometric);
+ @Deprecated
+ public boolean isCurrentUserUnlockedWithFace() {
+ return getFaceAuthInteractor() != null && getFaceAuthInteractor().isAuthenticated();
}
/**
@@ -1609,13 +1383,11 @@
*/
public boolean getUserUnlockedWithBiometricAndIsBypassing(int userId) {
BiometricAuthenticated fingerprint = mUserFingerprintAuthenticated.get(userId);
- BiometricAuthenticated face = mUserFaceAuthenticated.get(userId);
// fingerprint always bypasses
boolean fingerprintAllowed = fingerprint != null && fingerprint.mAuthenticated
&& isUnlockingWithBiometricAllowed(fingerprint.mIsStrongBiometric);
- boolean faceAllowed = face != null && face.mAuthenticated
- && isUnlockingWithBiometricAllowed(face.mIsStrongBiometric);
- return fingerprintAllowed || faceAllowed && mKeyguardBypassController.canBypass();
+ return fingerprintAllowed || (isCurrentUserUnlockedWithFace()
+ && mKeyguardBypassController.canBypass());
}
public boolean getUserTrustIsManaged(int userId) {
@@ -1684,10 +1456,22 @@
// STRONG_AUTH_REQUIRED_AFTER_LOCKOUT which is the same as mFingerprintLockedOutPermanent;
// however the strong auth tracker does not include the temporary lockout
// mFingerprintLockedOut.
+ if (!mStrongAuthTracker.isUnlockingWithBiometricAllowed(isStrongBiometric)) {
+ return false;
+ }
+ boolean isFaceLockedOut =
+ getFaceAuthInteractor() != null && getFaceAuthInteractor().isLockedOut();
+ boolean isFaceAuthStrong =
+ getFaceAuthInteractor() != null && getFaceAuthInteractor().isFaceAuthStrong();
+ boolean isFingerprintLockedOut = isFingerprintLockedOut();
+ boolean isAnyStrongBiometricLockedOut =
+ (isFingerprintClass3() && isFingerprintLockedOut) || (isFaceAuthStrong
+ && isFaceLockedOut);
// Class 3 biometric lockout will lockout ALL biometrics
- return mStrongAuthTracker.isUnlockingWithBiometricAllowed(isStrongBiometric)
- && (!isFingerprintClass3() || !isFingerprintLockedOut())
- && (!isFaceClass3() || !mFaceLockedOutPermanent);
+ if (isAnyStrongBiometricLockedOut) {
+ return false;
+ }
+ return !isFaceLockedOut || !isFingerprintLockedOut;
}
/**
@@ -1707,7 +1491,9 @@
case FINGERPRINT:
return isUnlockingWithBiometricAllowed(isFingerprintClass3());
case FACE:
- return isUnlockingWithBiometricAllowed(isFaceClass3());
+ return getFaceAuthInteractor() != null
+ && isUnlockingWithBiometricAllowed(
+ getFaceAuthInteractor().isFaceAuthStrong());
default:
return false;
}
@@ -1757,14 +1543,9 @@
}
}
if (userId == mSelectedUserInteractor.getSelectedUserId()) {
- FACE_AUTH_UPDATED_STRONG_AUTH_CHANGED.setExtraInfo(
- mStrongAuthTracker.getStrongAuthForUser(
- mSelectedUserInteractor.getSelectedUserId()));
-
// Strong auth is only reset when primary auth is used to enter the device,
// so we only check whether to stop biometric listening states here
- updateBiometricListeningState(
- BIOMETRIC_ACTION_STOP, FACE_AUTH_UPDATED_STRONG_AUTH_CHANGED);
+ updateFingerprintListeningState(BIOMETRIC_ACTION_STOP);
}
}
@@ -1787,14 +1568,9 @@
}
}
if (userId == mSelectedUserInteractor.getSelectedUserId()) {
- FACE_AUTH_NON_STRONG_BIOMETRIC_ALLOWED_CHANGED.setExtraInfo(
- mStrongAuthTracker.isNonStrongBiometricAllowedAfterIdleTimeout(
- mSelectedUserInteractor.getSelectedUserId()) ? -1 : 1);
-
// This is only reset when primary auth is used to enter the device, so we only check
// whether to stop biometric listening states here
- updateBiometricListeningState(BIOMETRIC_ACTION_STOP,
- FACE_AUTH_NON_STRONG_BIOMETRIC_ALLOWED_CHANGED);
+ updateFingerprintListeningState(BIOMETRIC_ACTION_STOP);
}
}
@@ -1813,11 +1589,10 @@
void setAssistantVisible(boolean assistantVisible) {
mAssistantVisible = assistantVisible;
mLogger.logAssistantVisible(mAssistantVisible);
- if (isFaceAuthInteractorEnabled()) {
- mFaceAuthInteractor.onAssistantTriggeredOnLockScreen();
+ if (getFaceAuthInteractor() != null) {
+ getFaceAuthInteractor().onAssistantTriggeredOnLockScreen();
}
- updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE,
- FACE_AUTH_UPDATED_ASSISTANT_VISIBILITY_CHANGED);
+ updateFingerprintListeningState(BIOMETRIC_ACTION_UPDATE);
if (mAssistantVisible) {
requestActiveUnlock(
ActiveUnlockConfig.ActiveUnlockRequestOrigin.ASSISTANT,
@@ -1929,14 +1704,6 @@
}
};
- private final FaceManager.LockoutResetCallback mFaceLockoutResetCallback
- = new FaceManager.LockoutResetCallback() {
- @Override
- public void onLockoutReset(int sensorId) {
- handleFaceLockoutReset(BIOMETRIC_LOCKOUT_NONE);
- }
- };
-
/**
* Propagates a pointer down event to keyguard.
*/
@@ -1998,7 +1765,6 @@
@Override
public void onUdfpsPointerDown(int sensorId) {
mLogger.logUdfpsPointerDown(sensorId);
- requestFaceAuth(FaceAuthApiRequestReason.UDFPS_POINTER_DOWN);
}
/**
@@ -2024,56 +1790,12 @@
}
};
- private final FaceManager.FaceDetectionCallback mFaceDetectionCallback
- = (sensorId, userId, isStrongBiometric) -> {
- // Trigger the face detected path so the bouncer can be shown
- handleBiometricDetected(userId, FACE, isStrongBiometric);
- };
-
- @VisibleForTesting
- final FaceManager.AuthenticationCallback mFaceAuthenticationCallback
- = new FaceManager.AuthenticationCallback() {
-
- @Override
- public void onAuthenticationFailed() {
- handleFaceAuthFailed();
- }
-
- @Override
- public void onAuthenticationSucceeded(FaceManager.AuthenticationResult result) {
- handleFaceAuthenticated(result.getUserId(), result.isStrongBiometric());
- }
-
- @Override
- public void onAuthenticationHelp(int helpMsgId, CharSequence helpString) {
- handleFaceHelp(helpMsgId, helpString.toString());
- }
-
- @Override
- public void onAuthenticationError(int errMsgId, CharSequence errString) {
- handleFaceError(errMsgId, errString.toString());
- }
-
- @Override
- public void onAuthenticationAcquired(int acquireInfo) {
- handleFaceAcquired(acquireInfo);
- }
- };
-
@VisibleForTesting
final DevicePostureController.Callback mPostureCallback =
new DevicePostureController.Callback() {
@Override
public void onPostureChanged(@DevicePostureInt int posture) {
- boolean currentPostureAllowsFaceAuth = doesPostureAllowFaceAuth(mPostureState);
- boolean newPostureAllowsFaceAuth = doesPostureAllowFaceAuth(posture);
- mPostureState = posture;
- if (currentPostureAllowsFaceAuth && !newPostureAllowsFaceAuth) {
- mLogger.d("New posture does not allow face auth, stopping it");
- updateFaceListeningState(BIOMETRIC_ACTION_STOP,
- FACE_AUTH_UPDATED_POSTURE_CHANGED);
- }
- if (mPostureState == DEVICE_POSTURE_OPENED) {
+ if (posture == DEVICE_POSTURE_OPENED) {
mLogger.d("Posture changed to open - attempting to request active unlock");
requestActiveUnlockFromWakeReason(PowerManager.WAKE_REASON_UNFOLD_DEVICE,
false);
@@ -2083,14 +1805,10 @@
@VisibleForTesting
CancellationSignal mFingerprintCancelSignal;
- @VisibleForTesting
- CancellationSignal mFaceCancelSignal;
private List<FingerprintSensorPropertiesInternal> mFingerprintSensorProperties =
Collections.emptyList();
- private List<FaceSensorPropertiesInternal> mFaceSensorProperties = Collections.emptyList();
private boolean mFingerprintLockedOut;
private boolean mFingerprintLockedOutPermanent;
- private boolean mFaceLockedOutPermanent;
/**
* When we receive a {@link android.content.Intent#ACTION_SIM_STATE_CHANGED} broadcast,
@@ -2229,15 +1947,7 @@
Trace.beginSection("KeyguardUpdateMonitor#handleStartedWakingUp");
Assert.isMainThread();
- mAllowedDisplayStateWhileAwakeForFaceAuth = true;
updateFingerprintListeningState(BIOMETRIC_ACTION_UPDATE);
- if (mFaceWakeUpTriggersConfig.shouldTriggerFaceAuthOnWakeUpFrom(pmWakeReason)) {
- FACE_AUTH_UPDATED_STARTED_WAKING_UP.setExtraInfo(pmWakeReason);
- updateFaceListeningState(BIOMETRIC_ACTION_UPDATE,
- FACE_AUTH_UPDATED_STARTED_WAKING_UP);
- } else {
- mLogger.logSkipUpdateFaceListeningOnWakeup(pmWakeReason);
- }
requestActiveUnlockFromWakeReason(pmWakeReason, true);
for (int i = 0; i < mCallbacks.size(); i++) {
@@ -2264,7 +1974,7 @@
// which results in face auth running once on AoD.
mAssistantVisible = false;
mLogger.d("Started going to sleep, mGoingToSleep=true, mAssistantVisible=false");
- updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE, FACE_AUTH_UPDATED_GOING_TO_SLEEP);
+ updateFingerprintListeningState(BIOMETRIC_ACTION_UPDATE);
}
protected void handleFinishedGoingToSleep(int arg1) {
@@ -2276,15 +1986,12 @@
cb.onFinishedGoingToSleep(arg1);
}
}
- updateFaceListeningState(BIOMETRIC_ACTION_STOP,
- FACE_AUTH_STOPPED_FINISHED_GOING_TO_SLEEP);
updateFingerprintListeningState(BIOMETRIC_ACTION_UPDATE);
}
private void handleScreenTurnedOff() {
Assert.isMainThread();
mHardwareFingerprintUnavailableRetryCount = 0;
- mHardwareFaceUnavailableRetryCount = 0;
}
private void handleDreamingStateChanged(int dreamStart) {
@@ -2297,9 +2004,6 @@
}
}
updateFingerprintListeningState(BIOMETRIC_ACTION_UPDATE);
- if (mIsDreaming) {
- updateFaceListeningState(BIOMETRIC_ACTION_STOP, FACE_AUTH_STOPPED_DREAM_STARTED);
- }
}
private void handleUserUnlocked(int userId) {
@@ -2344,7 +2048,6 @@
@VisibleForTesting
void resetBiometricListeningState() {
mFingerprintRunningState = BIOMETRIC_STATE_STOPPED;
- mFaceRunningState = BIOMETRIC_STATE_STOPPED;
}
@VisibleForTesting
@@ -2376,17 +2079,14 @@
SensorPrivacyManager sensorPrivacyManager,
TelephonyManager telephonyManager,
PackageManager packageManager,
- @Nullable FaceManager faceManager,
@Nullable FingerprintManager fingerprintManager,
@Nullable BiometricManager biometricManager,
FaceWakeUpTriggersConfig faceWakeUpTriggersConfig,
DevicePostureController devicePostureController,
Optional<FingerprintInteractiveToAuthProvider> interactiveToAuthProvider,
TaskStackChangeListeners taskStackChangeListeners,
- IActivityTaskManager activityTaskManagerService,
- DisplayTracker displayTracker,
- WakefulnessLifecycle wakefulness,
- SelectedUserInteractor selectedUserInteractor) {
+ SelectedUserInteractor selectedUserInteractor,
+ IActivityTaskManager activityTaskManagerService) {
mContext = context;
mSubscriptionManager = subscriptionManager;
mUserTracker = userTracker;
@@ -2413,16 +2113,9 @@
mDreamManager = dreamManager;
mTelephonyManager = telephonyManager;
mDevicePolicyManager = devicePolicyManager;
- mPostureController = devicePostureController;
mPackageManager = packageManager;
mFpm = fingerprintManager;
- mFaceManager = faceManager;
mActiveUnlockConfig.setKeyguardUpdateMonitor(this);
- mFaceAcquiredInfoIgnoreList = Arrays.stream(
- mContext.getResources().getIntArray(
- R.array.config_face_acquire_device_entry_ignorelist))
- .boxed()
- .collect(Collectors.toSet());
mConfigFaceAuthSupportedPosture = mContext.getResources().getInteger(
R.integer.config_face_auth_supported_posture);
mFaceWakeUpTriggersConfig = faceWakeUpTriggersConfig;
@@ -2432,9 +2125,6 @@
.collect(Collectors.toSet());
mTaskStackChangeListeners = taskStackChangeListeners;
mActivityTaskManager = activityTaskManagerService;
- mWakefulness = wakefulness;
- mDisplayTracker = displayTracker;
- mDisplayTracker.addDisplayChangeCallback(mDisplayCallback, mainExecutor);
mSelectedUserInteractor = selectedUserInteractor;
mHandler = new Handler(mainLooper) {
@@ -2521,8 +2211,7 @@
setAssistantVisible((boolean) msg.obj);
break;
case MSG_BIOMETRIC_AUTHENTICATION_CONTINUE:
- updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE,
- FACE_AUTH_UPDATED_FP_AUTHENTICATED);
+ updateFingerprintListeningState(BIOMETRIC_ACTION_UPDATE);
break;
case MSG_DEVICE_POLICY_MANAGER_STATE_CHANGED:
updateLogoutEnabled();
@@ -2617,18 +2306,6 @@
});
mFpm.addLockoutResetCallback(mFingerprintLockoutResetCallback);
}
- if (mFaceManager != null) {
- mFaceManager.addAuthenticatorsRegisteredCallback(
- new IFaceAuthenticatorsRegisteredCallback.Stub() {
- @Override
- public void onAllAuthenticatorsRegistered(
- List<FaceSensorPropertiesInternal> sensors) throws RemoteException {
- mFaceSensorProperties = sensors;
- mLogger.d("FaceManager onAllAuthenticatorsRegistered");
- }
- });
- mFaceManager.addLockoutResetCallback(mFaceLockoutResetCallback);
- }
if (biometricManager != null) {
biometricManager.registerEnabledOnKeyguardCallback(mBiometricEnabledCallback);
@@ -2639,16 +2316,16 @@
@Override
public void onAllAuthenticatorsRegistered(
@BiometricAuthenticator.Modality int modality) {
- mainExecutor.execute(() -> updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE,
- FACE_AUTH_TRIGGERED_ALL_AUTHENTICATORS_REGISTERED));
+ mainExecutor.execute(
+ () -> updateFingerprintListeningState(BIOMETRIC_ACTION_UPDATE));
}
@Override
public void onEnrollmentsChanged(@BiometricAuthenticator.Modality int modality) {
mHandler.obtainMessage(MSG_BIOMETRIC_ENROLLMENT_STATE_CHANGED, modality, 0)
.sendToTarget();
- mainExecutor.execute(() -> updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE,
- FACE_AUTH_TRIGGERED_ENROLLMENTS_CHANGED));
+ mainExecutor.execute(
+ () -> updateFingerprintListeningState(BIOMETRIC_ACTION_UPDATE));
}
@Override
@@ -2665,9 +2342,9 @@
}
});
if (mConfigFaceAuthSupportedPosture != DEVICE_POSTURE_UNKNOWN) {
- mPostureController.addCallback(mPostureCallback);
+ devicePostureController.addCallback(mPostureCallback);
}
- updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE, FACE_AUTH_UPDATED_ON_KEYGUARD_INIT);
+ updateFingerprintListeningState(BIOMETRIC_ACTION_UPDATE);
mTaskStackChangeListeners.registerTaskStackListener(mTaskStackListener);
mIsSystemUser = mUserManager.isSystemUser();
@@ -2721,10 +2398,6 @@
}
}
- private boolean isFaceSupported() {
- return mFaceManager != null && !mFaceSensorProperties.isEmpty();
- }
-
private boolean isFingerprintSupported() {
return mFpm != null && !mFingerprintSensorProperties.isEmpty();
}
@@ -2760,17 +2433,13 @@
}
/**
- * @return true if there's at least one face enrolled for the given user.
- */
- public boolean isFaceEnrolled(int userId) {
- return mAuthController.isFaceAuthEnrolled(userId);
- }
-
- /**
* @return true if there's at least one face enrolled
+ * @deprecated Use {@link KeyguardFaceAuthInteractor#isFaceAuthEnabledAndEnrolled()}
*/
- public boolean isFaceEnrolled() {
- return isFaceEnrolled(mSelectedUserInteractor.getSelectedUserId());
+ @Deprecated
+ public boolean isFaceEnabledAndEnrolled() {
+ return getFaceAuthInteractor() != null
+ && getFaceAuthInteractor().isFaceAuthEnabledAndEnrolled();
}
private final UserTracker.Callback mUserChangedCallback = new UserTracker.Callback() {
@@ -2798,12 +2467,6 @@
mHandler.sendEmptyMessage(MSG_AIRPLANE_MODE_CHANGED);
}
- private void updateBiometricListeningState(int action,
- @NonNull FaceAuthUiEvent faceAuthUiEvent) {
- updateFingerprintListeningState(action);
- updateFaceListeningState(action, faceAuthUiEvent);
- }
-
private void updateFingerprintListeningState(int action) {
// If this message exists, we should not authenticate again until this message is
// consumed by the handler
@@ -2859,57 +2522,9 @@
return;
}
mAuthInterruptActive = active;
- updateFaceListeningState(BIOMETRIC_ACTION_UPDATE,
- FACE_AUTH_TRIGGERED_ON_REACH_GESTURE_ON_AOD);
requestActiveUnlock(ActiveUnlockConfig.ActiveUnlockRequestOrigin.WAKE, "onReach");
}
- /**
- * Requests face authentication if we're on a state where it's allowed.
- * This will re-trigger auth in case it fails.
- * @param reason One of the reasons {@link FaceAuthApiRequestReason} on why this API is being
- * invoked.
- * @return current face auth detection state, true if it is running.
- * @deprecated This is being migrated to use modern architecture.
- */
- @Deprecated
- public boolean requestFaceAuth(@FaceAuthApiRequestReason String reason) {
- mLogger.logFaceAuthRequested(reason);
- updateFaceListeningState(BIOMETRIC_ACTION_START, apiRequestReasonToUiEvent(reason));
- return isFaceDetectionRunning();
- }
-
- /**
- * In case face auth is running, cancel it.
- */
- public void cancelFaceAuth() {
- stopListeningForFace(FACE_AUTH_STOPPED_USER_INPUT_ON_BOUNCER);
- }
-
- private void updateFaceListeningState(int action, @NonNull FaceAuthUiEvent faceAuthUiEvent) {
- if (isFaceAuthInteractorEnabled()) return;
- // If this message exists, we should not authenticate again until this message is
- // consumed by the handler
- if (mHandler.hasMessages(MSG_BIOMETRIC_AUTHENTICATION_CONTINUE)) {
- return;
- }
- mHandler.removeCallbacks(mRetryFaceAuthentication);
- boolean shouldListenForFace = shouldListenForFace();
- if (mFaceRunningState == BIOMETRIC_STATE_RUNNING && !shouldListenForFace) {
- if (action == BIOMETRIC_ACTION_START) {
- mLogger.v("Ignoring stopListeningForFace()");
- return;
- }
- stopListeningForFace(faceAuthUiEvent);
- } else if (mFaceRunningState != BIOMETRIC_STATE_RUNNING && shouldListenForFace) {
- if (action == BIOMETRIC_ACTION_STOP) {
- mLogger.v("Ignoring startListeningForFace()");
- return;
- }
- startListeningForFace(faceAuthUiEvent);
- }
- }
-
@Nullable
private InstanceId getKeyguardSessionId() {
return mSessionTrackerProvider.get().getSessionId(SESSION_KEYGUARD);
@@ -2994,8 +2609,9 @@
@NonNull ActiveUnlockConfig.ActiveUnlockRequestOrigin requestOrigin,
String extraReason
) {
- final boolean canFaceBypass = isFaceEnrolled() && mKeyguardBypassController != null
- && mKeyguardBypassController.canBypass();
+ final boolean canFaceBypass =
+ isFaceEnabledAndEnrolled() && mKeyguardBypassController != null
+ && mKeyguardBypassController.canBypass();
requestActiveUnlock(
requestOrigin,
extraReason, canFaceBypass
@@ -3022,8 +2638,6 @@
public void setAlternateBouncerShowing(boolean showing) {
mAlternateBouncerShowing = showing;
if (mAlternateBouncerShowing) {
- updateFaceListeningState(BIOMETRIC_ACTION_START,
- FACE_AUTH_TRIGGERED_ALTERNATE_BIOMETRIC_BOUNCER_SHOWN);
requestActiveUnlock(
ActiveUnlockConfig.ActiveUnlockRequestOrigin.UNLOCK_INTENT,
"alternateBouncer");
@@ -3101,17 +2715,6 @@
mSelectedUserInteractor.getSelectedUserId(), false);
}
- private boolean shouldListenForFaceAssistant() {
- BiometricAuthenticated face = mUserFaceAuthenticated.get(
- mSelectedUserInteractor.getSelectedUserId());
- return mAssistantVisible
- // There can be intermediate states where mKeyguardShowing is false but
- // mKeyguardOccluded is true, we don't want to run face auth in such a scenario.
- && (mKeyguardShowing && mKeyguardOccluded)
- && !(face != null && face.mAuthenticated)
- && !mUserHasTrust.get(mSelectedUserInteractor.getSelectedUserId(), false);
- }
-
private boolean shouldTriggerActiveUnlockForAssistant() {
return mAssistantVisible && mKeyguardOccluded
&& !mUserHasTrust.get(mSelectedUserInteractor.getSelectedUserId(), false);
@@ -3195,107 +2798,14 @@
/**
* If face auth is allows to scan on this exact moment.
+ *
+ * @deprecated Use {@link KeyguardFaceAuthInteractor#canFaceAuthRun()}
*/
+ @Deprecated
public boolean shouldListenForFace() {
- if (mFaceManager == null) {
- // Device does not have face auth
- return false;
- }
-
- if (isFaceAuthInteractorEnabled()) {
- return mFaceAuthInteractor.canFaceAuthRun();
- }
-
- final boolean statusBarShadeLocked = mStatusBarState == StatusBarState.SHADE_LOCKED;
- final boolean awakeKeyguard = isKeyguardVisible() && mDeviceInteractive
- && !statusBarShadeLocked;
- final int user = mSelectedUserInteractor.getSelectedUserId();
- final boolean faceAuthAllowed = isUnlockingWithBiometricAllowed(FACE);
- final boolean canBypass = mKeyguardBypassController != null
- && mKeyguardBypassController.canBypass();
- // There's no reason to ask the HAL for authentication when the user can dismiss the
- // bouncer because the user is trusted, unless we're bypassing and need to auto-dismiss
- // the lock screen even when TrustAgents are keeping the device unlocked.
- final boolean userNotTrustedOrDetectionIsNeeded = !getUserHasTrust(user) || canBypass;
-
- // If the device supports face detection (without authentication), if bypass is enabled,
- // allow face detection to happen even if stronger auth is required. When face is detected,
- // we show the bouncer. However, if the user manually locked down the device themselves,
- // never attempt to detect face.
- final boolean supportsDetect = isFaceSupported()
- && mFaceSensorProperties.get(0).supportsFaceDetection
- && canBypass && !mPrimaryBouncerIsOrWillBeShowing
- && !isUserInLockdown(user);
- final boolean faceAuthAllowedOrDetectionIsNeeded = faceAuthAllowed || supportsDetect;
-
- // If the face or fp has recently been authenticated do not attempt to authenticate again.
- final boolean faceAndFpNotAuthenticated = !getUserUnlockedWithBiometric(user);
- final boolean faceDisabledForUser = isFaceDisabled(user);
- final boolean biometricEnabledForUser = mBiometricEnabledForUser.get(user);
- final boolean shouldListenForFaceAssistant = shouldListenForFaceAssistant();
- final boolean isUdfpsFingerDown = mAuthController.isUdfpsFingerDown();
- final boolean isPostureAllowedForFaceAuth = doesPostureAllowFaceAuth(mPostureState);
- // Only listen if this KeyguardUpdateMonitor belongs to the system user. There is an
- // instance of KeyguardUpdateMonitor for each user but KeyguardUpdateMonitor is user-aware.
- final boolean shouldListen =
- (mPrimaryBouncerFullyShown
- || mAuthInterruptActive
- || mOccludingAppRequestingFace
- || awakeKeyguard
- || shouldListenForFaceAssistant
- || isUdfpsFingerDown
- || mAlternateBouncerShowing)
- && !mSwitchingUser && !faceDisabledForUser && userNotTrustedOrDetectionIsNeeded
- && !mKeyguardGoingAway && biometricEnabledForUser
- && faceAuthAllowedOrDetectionIsNeeded && mIsSystemUser
- && (!mSecureCameraLaunched || mAlternateBouncerShowing)
- && faceAndFpNotAuthenticated
- && !mGoingToSleep
- && isPostureAllowedForFaceAuth
- && mAllowedDisplayStateWhileAwakeForFaceAuth;
-
- // Aggregate relevant fields for debug logging.
- logListenerModelData(
- new KeyguardFaceListenModel(
- System.currentTimeMillis(),
- user,
- shouldListen,
- mAllowedDisplayStateWhileAwakeForFaceAuth,
- mAlternateBouncerShowing,
- mAuthInterruptActive,
- biometricEnabledForUser,
- mPrimaryBouncerFullyShown,
- faceAndFpNotAuthenticated,
- faceAuthAllowed,
- faceDisabledForUser,
- isFaceLockedOut(),
- mGoingToSleep,
- awakeKeyguard,
- mKeyguardGoingAway,
- shouldListenForFaceAssistant,
- mOccludingAppRequestingFace,
- isPostureAllowedForFaceAuth,
- mSecureCameraLaunched,
- supportsDetect,
- mSwitchingUser,
- mIsSystemUser,
- isUdfpsFingerDown,
- userNotTrustedOrDetectionIsNeeded));
-
- return shouldListen;
+ return getFaceAuthInteractor() != null && getFaceAuthInteractor().canFaceAuthRun();
}
- private boolean doesPostureAllowFaceAuth(@DevicePostureInt int posture) {
- return mConfigFaceAuthSupportedPosture == DEVICE_POSTURE_UNKNOWN
- || (posture == mConfigFaceAuthSupportedPosture);
- }
-
- /**
- * If the current device posture allows face auth to run.
- */
- public boolean doesCurrentPostureAllowFaceAuth() {
- return doesPostureAllowFaceAuth(mPostureState);
- }
private void logListenerModelData(@NonNull KeyguardListenModel model) {
mLogger.logKeyguardListenerModel(model);
@@ -3303,8 +2813,6 @@
mFingerprintListenBuffer.insert((KeyguardFingerprintListenModel) model);
} else if (model instanceof KeyguardActiveUnlockModel) {
mActiveUnlockTriggerBuffer.insert((KeyguardActiveUnlockModel) model);
- } else if (model instanceof KeyguardFaceListenModel) {
- mFaceListenBuffer.insert((KeyguardFaceListenModel) model);
}
}
@@ -3355,85 +2863,16 @@
}
}
- private void startListeningForFace(@NonNull FaceAuthUiEvent faceAuthUiEvent) {
- final int userId = mSelectedUserInteractor.getSelectedUserId();
- final boolean unlockPossible = isUnlockWithFacePossible(userId);
- if (mFaceCancelSignal != null) {
- mLogger.logUnexpectedFaceCancellationSignalState(mFaceRunningState, unlockPossible);
- }
-
- if (mFaceRunningState == BIOMETRIC_STATE_CANCELLING) {
- setFaceRunningState(BIOMETRIC_STATE_CANCELLING_RESTARTING);
- return;
- } else if (mFaceRunningState == BIOMETRIC_STATE_CANCELLING_RESTARTING) {
- // Waiting for ERROR_CANCELED before requesting auth again
- return;
- }
- mLogger.logStartedListeningForFace(mFaceRunningState, faceAuthUiEvent);
- mUiEventLogger.logWithInstanceIdAndPosition(
- faceAuthUiEvent,
- 0,
- null,
- getKeyguardSessionId(),
- faceAuthUiEvent.getExtraInfo()
- );
- mLogger.logFaceUnlockPossible(unlockPossible);
- if (unlockPossible) {
- mFaceCancelSignal = new CancellationSignal();
-
- final FaceAuthenticateOptions faceAuthenticateOptions =
- new SysUiFaceAuthenticateOptions(
- userId,
- faceAuthUiEvent,
- faceAuthUiEvent == FACE_AUTH_UPDATED_STARTED_WAKING_UP
- ? faceAuthUiEvent.getExtraInfo()
- : WAKE_REASON_UNKNOWN
- ).toFaceAuthenticateOptions();
- // This would need to be updated for multi-sensor devices
- final boolean supportsFaceDetection = isFaceSupported()
- && mFaceSensorProperties.get(0).supportsFaceDetection;
- if (!isUnlockingWithBiometricAllowed(FACE)) {
- final boolean udfpsFingerprintAuthRunning = isUdfpsSupported()
- && isFingerprintDetectionRunning();
- if (supportsFaceDetection && !udfpsFingerprintAuthRunning) {
- // Run face detection. (If a face is detected, show the bouncer.)
- mLogger.v("startListeningForFace - detect");
- mFaceManager.detectFace(mFaceCancelSignal, mFaceDetectionCallback,
- faceAuthenticateOptions);
- } else {
- // Don't run face detection. Instead, inform the user
- // face auth is unavailable and how to proceed.
- // (ie: "Use fingerprint instead" or "Swipe up to open")
- mLogger.v("Ignoring \"startListeningForFace - detect\". "
- + "Informing user face isn't available.");
- mFaceAuthenticationCallback.onAuthenticationHelp(
- BIOMETRIC_HELP_FACE_NOT_AVAILABLE,
- mContext.getResources().getString(
- R.string.keyguard_face_unlock_unavailable)
- );
- return;
- }
- } else {
- mLogger.v("startListeningForFace - authenticate");
- final boolean isBypassEnabled = mKeyguardBypassController != null
- && mKeyguardBypassController.isBypassEnabled();
- mFaceManager.authenticate(null /* crypto */, mFaceCancelSignal,
- mFaceAuthenticationCallback, null /* handler */,
- faceAuthenticateOptions);
- }
- setFaceRunningState(BIOMETRIC_STATE_RUNNING);
- }
- }
-
public boolean isFingerprintLockedOut() {
return mFingerprintLockedOut || mFingerprintLockedOutPermanent;
}
+ /**
+ * @deprecated Use {@link KeyguardFaceAuthInteractor#isLockedOut()}
+ */
+ @Deprecated
public boolean isFaceLockedOut() {
- if (isFaceAuthInteractorEnabled()) {
- return getFaceAuthInteractor().isLockedOut();
- }
- return mFaceLockedOutPermanent;
+ return getFaceAuthInteractor() != null && getFaceAuthInteractor().isLockedOut();
}
/**
@@ -3444,7 +2883,7 @@
* @return {@code true} if possible.
*/
public boolean isUnlockingWithBiometricsPossible(int userId) {
- return isUnlockWithFacePossible(userId) || isUnlockWithFingerprintPossible(userId);
+ return isUnlockWithFacePossible() || isUnlockWithFingerprintPossible(userId);
}
/**
@@ -3455,8 +2894,12 @@
* @return {@code true} if possible.
*/
public boolean isUnlockingWithNonStrongBiometricsPossible(int userId) {
- return (!isFaceClass3() && isUnlockWithFacePossible(userId))
- || (isFingerprintClass3() && isUnlockWithFingerprintPossible(userId));
+ if (getFaceAuthInteractor() != null && !getFaceAuthInteractor().isFaceAuthStrong()) {
+ if (isUnlockWithFacePossible()) {
+ return true;
+ }
+ }
+ return isFingerprintClass3() && isUnlockWithFingerprintPossible(userId);
}
@SuppressLint("MissingPermission")
@@ -3466,16 +2909,13 @@
}
/**
- * @deprecated This is being migrated to use modern architecture.
+ * @deprecated Use {@link KeyguardFaceAuthInteractor#isFaceAuthEnabledAndEnrolled()}
*/
@VisibleForTesting
@Deprecated
- public boolean isUnlockWithFacePossible(int userId) {
- if (isFaceAuthInteractorEnabled()) {
- return getFaceAuthInteractor() != null
+ public boolean isUnlockWithFacePossible() {
+ return getFaceAuthInteractor() != null
&& getFaceAuthInteractor().isFaceAuthEnabledAndEnrolled();
- }
- return isFaceSupported() && isFaceEnrolled(userId) && !isFaceDisabled(userId);
}
private void notifyAboutEnrollmentChange(@BiometricAuthenticator.Modality int modality) {
@@ -3513,25 +2953,6 @@
}
}
- private void stopListeningForFace(@NonNull FaceAuthUiEvent faceAuthUiEvent) {
- if (isFaceAuthInteractorEnabled()) return;
- mLogger.v("stopListeningForFace()");
- mLogger.logStoppedListeningForFace(mFaceRunningState, faceAuthUiEvent.getReason());
- mUiEventLogger.log(faceAuthUiEvent, getKeyguardSessionId());
- if (mFaceRunningState == BIOMETRIC_STATE_RUNNING) {
- if (mFaceCancelSignal != null) {
- mFaceCancelSignal.cancel();
- mFaceCancelSignal = null;
- mHandler.removeCallbacks(mFaceCancelNotReceived);
- mHandler.postDelayed(mFaceCancelNotReceived, DEFAULT_CANCEL_SIGNAL_TIMEOUT);
- }
- setFaceRunningState(BIOMETRIC_STATE_CANCELLING);
- }
- if (mFaceRunningState == BIOMETRIC_STATE_CANCELLING_RESTARTING) {
- setFaceRunningState(BIOMETRIC_STATE_CANCELLING);
- }
- }
-
private boolean isDeviceProvisionedInSettingsDb() {
return Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.DEVICE_PROVISIONED, 0) != 0;
@@ -3617,13 +3038,6 @@
}
}
- // Immediately stop previous biometric listening states.
- // Resetting lockout states updates the biometric listening states.
- if (isFaceSupported()) {
- stopListeningForFace(FACE_AUTH_UPDATED_USER_SWITCHING);
- handleFaceLockoutReset(mFaceManager.getLockoutModeForUser(
- mFaceSensorProperties.get(0).sensorId, userId));
- }
if (isFingerprintSupported()) {
stopListeningForFingerprint();
handleFingerprintLockoutReset(mFpm.getLockoutModeForUser(
@@ -3866,8 +3280,7 @@
@VisibleForTesting
protected void handleKeyguardReset() {
mLogger.d("handleKeyguardReset");
- updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE,
- FACE_AUTH_UPDATED_KEYGUARD_RESET);
+ updateFingerprintListeningState(BIOMETRIC_ACTION_UPDATE);
mNeedsSlowUnlockTransition = resolveNeedsSlowUnlockTransition();
}
@@ -3935,8 +3348,6 @@
cb.onKeyguardBouncerFullyShowingChanged(mPrimaryBouncerFullyShown);
}
}
- updateFaceListeningState(BIOMETRIC_ACTION_UPDATE,
- FACE_AUTH_UPDATED_PRIMARY_BOUNCER_SHOWN);
}
}
@@ -4071,8 +3482,7 @@
}
mSwitchingUser = switching;
// Since this comes in on a binder thread, we need to post it first
- mHandler.post(() -> updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE,
- FACE_AUTH_UPDATED_USER_SWITCHING));
+ mHandler.post(() -> updateFingerprintListeningState(BIOMETRIC_ACTION_UPDATE));
}
private void sendUpdates(KeyguardUpdateMonitorCallback callback) {
@@ -4161,7 +3571,6 @@
private void clearBiometricRecognized(int unlockedUser) {
Assert.isMainThread();
mUserFingerprintAuthenticated.clear();
- mUserFaceAuthenticated.clear();
mTrustManager.clearAllBiometricRecognized(FINGERPRINT, unlockedUser);
mTrustManager.clearAllBiometricRecognized(FACE, unlockedUser);
mLogger.d("clearBiometricRecognized");
@@ -4394,12 +3803,6 @@
return isFingerprintSupported() && isClass3Biometric(mFingerprintSensorProperties.get(0));
}
- @VisibleForTesting
- protected boolean isFaceClass3() {
- // This assumes that there is at most one face sensor property
- return isFaceSupported() && isClass3Biometric(mFaceSensorProperties.get(0));
- }
-
private boolean isClass3Biometric(SensorPropertiesInternal sensorProperties) {
return sensorProperties.sensorStrength == SensorProperties.STRENGTH_STRONG;
}
@@ -4411,8 +3814,8 @@
mStatusBarStateController.removeCallback(mStatusBarStateControllerListener);
mTelephonyListenerManager.removeActiveDataSubscriptionIdListener(mPhoneStateListener);
mSubscriptionManager.removeOnSubscriptionsChangedListener(mSubscriptionListener);
- if (isFaceAuthInteractorEnabled()) {
- mFaceAuthInteractor.unregisterListener(mFaceAuthenticationListener);
+ if (getFaceAuthInteractor() != null) {
+ getFaceAuthInteractor().unregisterListener(mFaceAuthenticationListener);
}
if (mDeviceProvisionedObserver != null) {
@@ -4432,7 +3835,6 @@
mLockPatternUtils.unregisterStrongAuthTracker(mStrongAuthTracker);
mTrustManager.unregisterTrustListener(this);
- mDisplayTracker.removeCallback(mDisplayCallback);
mHandler.removeCallbacksAndMessages(null);
}
@@ -4446,7 +3848,6 @@
mSelectedUserInteractor.getSelectedUserId()));
pw.println(" getUserUnlockedWithBiometric()="
+ getUserUnlockedWithBiometric(mSelectedUserInteractor.getSelectedUserId()));
- pw.println(" isFaceAuthInteractorEnabled: " + isFaceAuthInteractorEnabled());
pw.println(" SIM States:");
for (SimData data : mSimDatas.values()) {
pw.println(" " + data.toString());
@@ -4519,50 +3920,11 @@
mFingerprintListenBuffer.toList()
).printTableData(pw);
}
- if (isFaceSupported()) {
- final int userId = mSelectedUserInteractor.getSelectedUserId(true);
- final int strongAuthFlags = mStrongAuthTracker.getStrongAuthForUser(userId);
- BiometricAuthenticated face = mUserFaceAuthenticated.get(userId);
- pw.println(" Face authentication state (user=" + userId + ")");
- pw.println(" isFaceClass3=" + isFaceClass3());
- pw.println(" allowed="
- + (face != null && isUnlockingWithBiometricAllowed(face.mIsStrongBiometric)));
- pw.println(" auth'd="
- + (face != null && face.mAuthenticated));
- pw.println(" authSinceBoot="
- + getStrongAuthTracker().hasUserAuthenticatedSinceBoot());
- pw.println(" disabled(DPM)=" + isFaceDisabled(userId));
- pw.println(" possible=" + isUnlockWithFacePossible(userId));
- pw.println(" listening: actual=" + mFaceRunningState
- + " expected=(" + (shouldListenForFace() ? 1 : 0));
- pw.println(" strongAuthFlags=" + Integer.toHexString(strongAuthFlags));
- pw.println(" isNonStrongBiometricAllowedAfterIdleTimeout="
- + mStrongAuthTracker.isNonStrongBiometricAllowedAfterIdleTimeout(userId));
- pw.println(" trustManaged=" + getUserTrustIsManaged(userId));
- pw.println(" mFaceLockedOutPermanent=" + mFaceLockedOutPermanent);
- pw.println(" enabledByUser=" + mBiometricEnabledForUser.get(userId));
- pw.println(" mSecureCameraLaunched=" + mSecureCameraLaunched);
- pw.println(" mPrimaryBouncerFullyShown=" + mPrimaryBouncerFullyShown);
- pw.println(" mNeedsSlowUnlockTransition=" + mNeedsSlowUnlockTransition);
- new DumpsysTableLogger(
- "KeyguardFaceListen",
- KeyguardFaceListenModel.TABLE_HEADERS,
- mFaceListenBuffer.toList()
- ).printTableData(pw);
- } else if (mFaceManager != null && mFaceSensorProperties.isEmpty()) {
- final int userId = mSelectedUserInteractor.getSelectedUserId(true);
- pw.println(" Face state (user=" + userId + ")");
- pw.println(" mFaceSensorProperties.isEmpty="
- + mFaceSensorProperties.isEmpty());
- pw.println(" mFaceManager.isHardwareDetected="
- + mFaceManager.isHardwareDetected());
-
- new DumpsysTableLogger(
- "KeyguardFaceListen",
- KeyguardFingerprintListenModel.TABLE_HEADERS,
- mFingerprintListenBuffer.toList()
- ).printTableData(pw);
- }
+ final int userId = mSelectedUserInteractor.getSelectedUserId(true);
+ final int strongAuthFlags = mStrongAuthTracker.getStrongAuthForUser(userId);
+ pw.println(" authSinceBoot="
+ + getStrongAuthTracker().hasUserAuthenticatedSinceBoot());
+ pw.println(" strongAuthFlags=" + Integer.toHexString(strongAuthFlags));
pw.println("ActiveUnlockRunning="
+ mTrustManager.isActiveUnlockRunning(mSelectedUserInteractor.getSelectedUserId()));
new DumpsysTableLogger(
@@ -4577,13 +3939,8 @@
* Cancels all operations in the scheduler if it is hung for 10 seconds.
*/
public void startBiometricWatchdog() {
- final boolean isFaceAuthInteractorEnabled = isFaceAuthInteractorEnabled();
mBackgroundExecutor.execute(() -> {
Trace.beginSection("#startBiometricWatchdog");
- if (mFaceManager != null && !isFaceAuthInteractorEnabled) {
- mLogger.scheduleWatchdog("face");
- mFaceManager.scheduleWatchdog();
- }
if (mFpm != null) {
mLogger.scheduleWatchdog("fingerprint");
mFpm.scheduleWatchdog();
diff --git a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt
index 5bf8d63..055ca56 100644
--- a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt
+++ b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt
@@ -20,14 +20,12 @@
import android.hardware.biometrics.BiometricConstants.LockoutMode
import android.hardware.biometrics.BiometricSourceType
import android.os.PowerManager
-import android.os.PowerManager.WakeReason
import android.telephony.ServiceState
import android.telephony.SubscriptionInfo
import android.telephony.SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX
import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
import android.telephony.TelephonyManager
import com.android.keyguard.ActiveUnlockConfig
-import com.android.keyguard.FaceAuthUiEvent
import com.android.keyguard.KeyguardListenModel
import com.android.keyguard.KeyguardUpdateMonitorCallback
import com.android.keyguard.TrustGrantFlags
@@ -102,14 +100,6 @@
logBuffer.log(TAG, ERROR, {}, { logMsg }, exception = ex)
}
- fun logFaceAuthDisabledForUser(userId: Int) {
- logBuffer.log(
- TAG,
- DEBUG,
- { int1 = userId },
- { "Face authentication disabled by DPM for userId: $int1" }
- )
- }
fun logFaceAuthError(msgId: Int, originalErrMsg: String) {
logBuffer.log(
TAG,
@@ -131,31 +121,10 @@
)
}
- fun logFaceAuthRequested(reason: String?) {
- logBuffer.log(TAG, DEBUG, { str1 = reason }, { "requestFaceAuth() reason=$str1" })
- }
-
fun logFaceAuthSuccess(userId: Int) {
logBuffer.log(TAG, DEBUG, { int1 = userId }, { "Face auth succeeded for user $int1" })
}
- fun logFaceLockoutReset(@LockoutMode mode: Int) {
- logBuffer.log(TAG, DEBUG, { int1 = mode }, { "handleFaceLockoutReset: $int1" })
- }
-
- fun logFaceRunningState(faceRunningState: Int) {
- logBuffer.log(TAG, DEBUG, { int1 = faceRunningState }, { "faceRunningState: $int1" })
- }
-
- fun logFaceUnlockPossible(isFaceUnlockPossible: Boolean) {
- logBuffer.log(
- TAG,
- DEBUG,
- { bool1 = isFaceUnlockPossible },
- { "isUnlockWithFacePossible: $bool1" }
- )
- }
-
fun logFingerprintAuthForWrongUser(authUserId: Int) {
logBuffer.log(
FP_LOG_TAG,
@@ -301,15 +270,6 @@
logBuffer.log(TAG, VERBOSE, { str1 = "$callback" }, { "*** register callback for $str1" })
}
- fun logRetryingAfterFaceHwUnavailable(retryCount: Int) {
- logBuffer.log(
- TAG,
- WARNING,
- { int1 = retryCount },
- { "Retrying face after HW unavailable, attempt $int1" }
- )
- }
-
fun logRetryAfterFpErrorWithDelay(msgId: Int, errString: String?, delay: Int) {
logBuffer.log(
TAG,
@@ -419,43 +379,6 @@
logBuffer.log(TAG, VERBOSE, { int1 = subId }, { "reportSimUnlocked(subId=$int1)" })
}
- fun logStartedListeningForFace(faceRunningState: Int, faceAuthUiEvent: FaceAuthUiEvent) {
- logBuffer.log(
- TAG,
- VERBOSE,
- {
- int1 = faceRunningState
- str1 = faceAuthUiEvent.reason
- str2 = faceAuthUiEvent.extraInfoToString()
- },
- { "startListeningForFace(): $int1, reason: $str1 $str2" }
- )
- }
-
- fun logStartedListeningForFaceFromWakeUp(faceRunningState: Int, @WakeReason pmWakeReason: Int) {
- logBuffer.log(
- TAG,
- VERBOSE,
- {
- int1 = faceRunningState
- str1 = PowerManager.wakeReasonToString(pmWakeReason)
- },
- { "startListeningForFace(): $int1, reason: wakeUp-$str1" }
- )
- }
-
- fun logStoppedListeningForFace(faceRunningState: Int, faceAuthReason: String) {
- logBuffer.log(
- TAG,
- VERBOSE,
- {
- int1 = faceRunningState
- str1 = faceAuthReason
- },
- { "stopListeningForFace(): currentFaceRunningState: $int1, reason: $str1" }
- )
- }
-
fun logSubInfo(subInfo: SubscriptionInfo?) {
logBuffer.log(TAG, DEBUG, { str1 = "$subInfo" }, { "SubInfo:$str1" })
}
@@ -476,22 +399,6 @@
logBuffer.log(TAG, DEBUG, { int1 = sensorId }, { "onUdfpsPointerUp, sensorId: $int1" })
}
- fun logUnexpectedFaceCancellationSignalState(faceRunningState: Int, unlockPossible: Boolean) {
- logBuffer.log(
- TAG,
- ERROR,
- {
- int1 = faceRunningState
- bool1 = unlockPossible
- },
- {
- "Cancellation signal is not null, high chance of bug in " +
- "face auth lifecycle management. " +
- "Face state: $int1, unlockPossible: $bool1"
- }
- )
- }
-
fun logUnexpectedFpCancellationSignalState(
fingerprintRunningState: Int,
unlockPossible: Boolean
@@ -588,15 +495,6 @@
)
}
- fun logSkipUpdateFaceListeningOnWakeup(@WakeReason pmWakeReason: Int) {
- logBuffer.log(
- TAG,
- VERBOSE,
- { str1 = PowerManager.wakeReasonToString(pmWakeReason) },
- { "Skip updating face listening state on wakeup from $str1" }
- )
- }
-
fun logTaskStackChangedForAssistant(assistantVisible: Boolean) {
logBuffer.log(
TAG,
@@ -648,18 +546,6 @@
)
}
- fun logFaceEnrolledUpdated(oldValue: Boolean, newValue: Boolean) {
- logBuffer.log(
- TAG,
- DEBUG,
- {
- bool1 = oldValue
- bool2 = newValue
- },
- { "Face enrolled state changed: old: $bool1, new: $bool2" }
- )
- }
-
fun logTrustUsuallyManagedUpdated(
userId: Int,
oldValue: Boolean,
@@ -745,18 +631,6 @@
)
}
- fun logFingerprintHelp(helpMsgId: Int, helpString: CharSequence) {
- logBuffer.log(
- FP_LOG_TAG,
- DEBUG,
- {
- int1 = helpMsgId
- str1 = "$helpString"
- },
- { "fingerprint help message: $int1, $str1" }
- )
- }
-
fun logFingerprintAcquired(acquireInfo: Int) {
logBuffer.log(
FP_LOG_TAG,
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/FaceAuthAccessibilityDelegate.kt b/packages/SystemUI/src/com/android/systemui/biometrics/FaceAuthAccessibilityDelegate.kt
index bbdcadb..cb75049 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/FaceAuthAccessibilityDelegate.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/FaceAuthAccessibilityDelegate.kt
@@ -20,12 +20,10 @@
import android.os.Bundle
import android.view.View
import android.view.accessibility.AccessibilityNodeInfo
-import com.android.keyguard.FaceAuthApiRequestReason
-import com.android.keyguard.KeyguardUpdateMonitor
-import com.android.systemui.res.R
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor
+import com.android.systemui.res.R
import javax.inject.Inject
/**
@@ -37,12 +35,11 @@
@Inject
constructor(
@Main private val resources: Resources,
- private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
private val faceAuthInteractor: KeyguardFaceAuthInteractor,
) : View.AccessibilityDelegate() {
override fun onInitializeAccessibilityNodeInfo(host: View, info: AccessibilityNodeInfo) {
super.onInitializeAccessibilityNodeInfo(host, info)
- if (keyguardUpdateMonitor.shouldListenForFace()) {
+ if (faceAuthInteractor.canFaceAuthRun()) {
val clickActionToRetryFace =
AccessibilityNodeInfo.AccessibilityAction(
AccessibilityNodeInfo.AccessibilityAction.ACTION_CLICK.id,
@@ -54,7 +51,6 @@
override fun performAccessibilityAction(host: View, action: Int, args: Bundle?): Boolean {
return if (action == AccessibilityNodeInfo.AccessibilityAction.ACTION_CLICK.id) {
- keyguardUpdateMonitor.requestFaceAuth(FaceAuthApiRequestReason.ACCESSIBILITY_ACTION)
faceAuthInteractor.onAccessibilityAction()
true
} else super.performAccessibilityAction(host, action, args)
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index e15538b..72d14ba 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -64,7 +64,6 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.InstanceId;
import com.android.internal.util.LatencyTracker;
-import com.android.keyguard.FaceAuthApiRequestReason;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.Dumpable;
import com.android.systemui.animation.ActivityLaunchAnimator;
@@ -103,8 +102,6 @@
import com.android.systemui.util.concurrency.Execution;
import com.android.systemui.util.time.SystemClock;
-import kotlin.Unit;
-
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashSet;
@@ -114,6 +111,8 @@
import javax.inject.Inject;
import javax.inject.Provider;
+import kotlin.Unit;
+
import kotlinx.coroutines.ExperimentalCoroutinesApi;
/**
@@ -589,7 +588,8 @@
// Always pilfer pointers that are within sensor area or when alternate bouncer is showing
if (mActivePointerId != MotionEvent.INVALID_POINTER_ID
- || mAlternateBouncerInteractor.isVisibleState()) {
+ || (mAlternateBouncerInteractor.isVisibleState()
+ && !DeviceEntryUdfpsRefactor.isEnabled())) {
shouldPilfer = true;
}
@@ -1013,9 +1013,6 @@
playStartHaptic();
mKeyguardFaceAuthInteractor.onUdfpsSensorTouched();
- if (!mKeyguardUpdateMonitor.isFaceDetectionRunning()) {
- mKeyguardUpdateMonitor.requestFaceAuth(FaceAuthApiRequestReason.UDFPS_POINTER_DOWN);
- }
}
mOnFingerDown = true;
mFingerprintManager.onPointerDown(requestId, mSensorProps.sensorId, pointerId, x, y,
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerLegacy.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerLegacy.kt
index 35c3ded..6954eb6 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerLegacy.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerLegacy.kt
@@ -50,7 +50,6 @@
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.map
-import kotlinx.coroutines.flow.merge
import kotlinx.coroutines.launch
/** Class that coordinates non-HBM animations during keyguard authentication. */
@@ -215,12 +214,12 @@
suspend fun listenForLockscreenAodTransitions(scope: CoroutineScope): Job {
return scope.launch {
transitionInteractor.dozeAmountTransition.collect { transitionStep ->
- view.onDozeAmountChanged(
- transitionStep.value,
- transitionStep.value,
- UdfpsKeyguardViewLegacy.ANIMATION_BETWEEN_AOD_AND_LOCKSCREEN,
- )
- }
+ view.onDozeAmountChanged(
+ transitionStep.value,
+ transitionStep.value,
+ UdfpsKeyguardViewLegacy.ANIMATION_BETWEEN_AOD_AND_LOCKSCREEN,
+ )
+ }
}
}
@@ -286,7 +285,6 @@
keyguardStateController.removeCallback(keyguardStateControllerCallback)
statusBarStateController.removeCallback(stateListener)
keyguardViewManager.removeOccludingAppBiometricUI(occludingAppBiometricUI)
- keyguardUpdateMonitor.requestFaceAuthOnOccludingApp(false)
configurationController.removeCallback(configurationListener)
if (lockScreenShadeTransitionController.mUdfpsKeyguardViewControllerLegacy === this) {
lockScreenShadeTransitionController.mUdfpsKeyguardViewControllerLegacy = null
@@ -334,14 +332,9 @@
if (udfpsAffordanceWasNotShowing) {
view.animateInUdfpsBouncer(null)
}
- if (keyguardStateController.isOccluded) {
- keyguardUpdateMonitor.requestFaceAuthOnOccludingApp(true)
- }
view.announceForAccessibility(
view.context.getString(R.string.accessibility_fingerprint_bouncer)
)
- } else {
- keyguardUpdateMonitor.requestFaceAuthOnOccludingApp(false)
}
updateAlpha()
updatePauseAuth()
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractor.kt b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractor.kt
index 56dfa5ed..aa7758f 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractor.kt
@@ -39,6 +39,7 @@
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.keyguard.DismissCallbackRegistry
import com.android.systemui.keyguard.data.repository.TrustRepository
+import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.res.R
import com.android.systemui.shared.system.SysUiStatsLog
@@ -75,6 +76,7 @@
private val trustRepository: TrustRepository,
@Application private val applicationScope: CoroutineScope,
private val selectedUserInteractor: SelectedUserInteractor,
+ private val keyguardFaceAuthInteractor: KeyguardFaceAuthInteractor,
) {
private val passiveAuthBouncerDelay =
context.resources.getInteger(R.integer.primary_bouncer_passive_auth_delay).toLong()
@@ -414,15 +416,12 @@
/** Whether we want to wait to show the bouncer in case passive auth succeeds. */
private fun usePrimaryBouncerPassiveAuthDelay(): Boolean {
- val canRunFaceAuth =
- keyguardStateController.isFaceEnrolled &&
- keyguardUpdateMonitor.isUnlockingWithBiometricAllowed(BiometricSourceType.FACE) &&
- keyguardUpdateMonitor.doesCurrentPostureAllowFaceAuth()
val canRunActiveUnlock =
currentUserActiveUnlockRunning &&
keyguardUpdateMonitor.canTriggerActiveUnlockBasedOnDeviceState()
- return !needsFullscreenBouncer() && (canRunFaceAuth || canRunActiveUnlock)
+ return !needsFullscreenBouncer() &&
+ (keyguardFaceAuthInteractor.canFaceAuthRun() || canRunActiveUnlock)
}
companion object {
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/Classifier.java b/packages/SystemUI/src/com/android/systemui/classifier/Classifier.java
index 334cf93..740e8bb 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/Classifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/Classifier.java
@@ -45,6 +45,7 @@
public static final int BACK_GESTURE = 16;
public static final int QS_SWIPE_NESTED = 17;
public static final int MEDIA_SEEKBAR = 18;
+ public static final int ALTERNATE_BOUNCER_SWIPE = 19;
@IntDef({
QUICK_SETTINGS,
@@ -65,6 +66,7 @@
QS_SWIPE_NESTED,
BACK_GESTURE,
MEDIA_SEEKBAR,
+ ALTERNATE_BOUNCER_SWIPE,
})
@Retention(RetentionPolicy.SOURCE)
public @interface InteractionType {}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/DistanceClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/DistanceClassifier.java
index 15e2e9a..b13bf4e 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/DistanceClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/DistanceClassifier.java
@@ -22,6 +22,7 @@
import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHTLINE_FALSING_DISTANCE_VELOCITY_TO_DISTANCE;
import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHTLINE_FALSING_DISTANCE_VERTICAL_FLING_THRESHOLD_IN;
import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHTLINE_FALSING_DISTANCE_VERTICAL_SWIPE_THRESHOLD_IN;
+import static com.android.systemui.classifier.Classifier.ALTERNATE_BOUNCER_SWIPE;
import static com.android.systemui.classifier.Classifier.BRIGHTNESS_SLIDER;
import static com.android.systemui.classifier.Classifier.MEDIA_SEEKBAR;
import static com.android.systemui.classifier.Classifier.QS_COLLAPSE;
@@ -159,7 +160,8 @@
|| interactionType == QS_COLLAPSE
|| interactionType == Classifier.UDFPS_AUTHENTICATION
|| interactionType == Classifier.QS_SWIPE_SIDE
- || interactionType == QS_SWIPE_NESTED) {
+ || interactionType == QS_SWIPE_NESTED
+ || interactionType == ALTERNATE_BOUNCER_SWIPE) {
return Result.passed(0);
}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/TypeClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/TypeClassifier.java
index 2fb6aaf..93aa279 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/TypeClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/TypeClassifier.java
@@ -17,6 +17,7 @@
package com.android.systemui.classifier;
+import static com.android.systemui.classifier.Classifier.ALTERNATE_BOUNCER_SWIPE;
import static com.android.systemui.classifier.Classifier.BOUNCER_UNLOCK;
import static com.android.systemui.classifier.Classifier.BRIGHTNESS_SLIDER;
import static com.android.systemui.classifier.Classifier.LEFT_AFFORDANCE;
@@ -73,6 +74,7 @@
case NOTIFICATION_DISMISS:
wrongDirection = vertical;
break;
+ case ALTERNATE_BOUNCER_SWIPE:
case UNLOCK:
case BOUNCER_UNLOCK:
wrongDirection = !vertical || !up;
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
index dcacd09..d9e0629 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
@@ -34,10 +34,8 @@
import com.android.systemui.unfold.FoldStateLogger;
import com.android.systemui.unfold.FoldStateLoggingProvider;
import com.android.systemui.unfold.SysUIUnfoldComponent;
-import com.android.systemui.unfold.UnfoldLatencyTracker;
import com.android.systemui.unfold.UnfoldTransitionProgressProvider;
import com.android.systemui.unfold.progress.UnfoldTransitionProgressForwarder;
-import com.android.systemui.unfold.util.NaturalRotationUnfoldProgressProvider;
import com.android.wm.shell.back.BackAnimation;
import com.android.wm.shell.bubbles.Bubbles;
import com.android.wm.shell.desktopmode.DesktopMode;
@@ -62,7 +60,7 @@
/**
* An example Dagger Subcomponent for Core SysUI.
- *
+ * <p>
* See {@link ReferenceSysUIComponent} for the one actually used by AOSP.
*/
@SysUISingleton
@@ -131,23 +129,26 @@
default void init() {
// Initialize components that have no direct tie to the dagger dependency graph,
// but are critical to this component's operation
- getSysUIUnfoldComponent().ifPresent(c -> {
- c.getUnfoldLightRevealOverlayAnimation().init();
- c.getUnfoldTransitionWallpaperController().init();
- c.getUnfoldHapticsPlayer();
- });
- getNaturalRotationUnfoldProgressProvider().ifPresent(o -> o.init());
+ getSysUIUnfoldComponent()
+ .ifPresent(
+ c -> {
+ c.getUnfoldLightRevealOverlayAnimation().init();
+ c.getUnfoldTransitionWallpaperController().init();
+ c.getUnfoldHapticsPlayer();
+ c.getNaturalRotationUnfoldProgressProvider().init();
+ c.getUnfoldLatencyTracker().init();
+ });
// No init method needed, just needs to be gotten so that it's created.
getMediaMuteAwaitConnectionCli();
getNearbyMediaDevicesManager();
- getUnfoldLatencyTracker().init();
getConnectingDisplayViewModel().init();
getFoldStateLoggingProvider().ifPresent(FoldStateLoggingProvider::init);
getFoldStateLogger().ifPresent(FoldStateLogger::init);
- getUnfoldTransitionProgressProvider().ifPresent((progressProvider) ->
- getUnfoldTransitionProgressForwarder().ifPresent((forwarder) ->
- progressProvider.addCallback(forwarder)
- ));
+ getUnfoldTransitionProgressProvider()
+ .ifPresent(
+ (progressProvider) ->
+ getUnfoldTransitionProgressForwarder()
+ .ifPresent(progressProvider::addCallback));
}
/**
@@ -169,12 +170,6 @@
ContextComponentHelper getContextComponentHelper();
/**
- * Creates a UnfoldLatencyTracker.
- */
- @SysUISingleton
- UnfoldLatencyTracker getUnfoldLatencyTracker();
-
- /**
* Creates a UnfoldTransitionProgressProvider.
*/
@SysUISingleton
@@ -219,11 +214,6 @@
*/
Optional<SysUIUnfoldComponent> getSysUIUnfoldComponent();
- /**
- * For devices with a hinge: the rotation animation
- */
- Optional<NaturalRotationUnfoldProgressProvider> getNaturalRotationUnfoldProgressProvider();
-
/** */
MediaMuteAwaitConnectionCli getMediaMuteAwaitConnectionCli();
diff --git a/packages/SystemUI/src/com/android/systemui/decor/FaceScanningProviderFactory.kt b/packages/SystemUI/src/com/android/systemui/decor/FaceScanningProviderFactory.kt
index 31a5d37..4bfc9484 100644
--- a/packages/SystemUI/src/com/android/systemui/decor/FaceScanningProviderFactory.kt
+++ b/packages/SystemUI/src/com/android/systemui/decor/FaceScanningProviderFactory.kt
@@ -97,7 +97,7 @@
}
fun canShowFaceScanningAnim(): Boolean {
- return hasProviders && keyguardUpdateMonitor.isFaceEnrolled
+ return hasProviders && keyguardUpdateMonitor.isFaceEnabledAndEnrolled
}
fun shouldShowFaceScanningAnim(): Boolean {
diff --git a/packages/SystemUI/src/com/android/systemui/flags/FlagDependencies.kt b/packages/SystemUI/src/com/android/systemui/flags/FlagDependencies.kt
index 83c16ae..6a0e882 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/FlagDependencies.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/FlagDependencies.kt
@@ -19,6 +19,7 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.statusbar.notification.footer.shared.FooterViewRefactor
import com.android.systemui.statusbar.notification.shared.NotificationIconContainerRefactor
+import com.android.systemui.statusbar.notification.shared.NotificationsLiveDataStoreRefactor
import javax.inject.Inject
/** A class in which engineers can define flag dependencies */
@@ -26,6 +27,7 @@
class FlagDependencies @Inject constructor(featureFlags: FeatureFlagsClassic, handler: Handler) :
FlagDependenciesBase(featureFlags, handler) {
override fun defineDependencies() {
+ NotificationsLiveDataStoreRefactor.token dependsOn NotificationIconContainerRefactor.token
FooterViewRefactor.token dependsOn NotificationIconContainerRefactor.token
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index 98fda3e..e6f1a54 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -152,10 +152,6 @@
@JvmField
val REFACTOR_GETCURRENTUSER = unreleasedFlag("refactor_getcurrentuser", teamfood = true)
- /** Flag to control the migration of face auth to modern architecture. */
- // TODO(b/262838215): Tracking bug
- @JvmField val FACE_AUTH_REFACTOR = releasedFlag("face_auth_refactor")
-
/** Flag to control the revamp of keyguard biometrics progress animation */
// TODO(b/244313043): Tracking bug
@JvmField val BIOMETRICS_ANIMATION_REVAMP = unreleasedFlag("biometrics_animation_revamp")
@@ -630,7 +626,7 @@
// TODO(b/277201412): Tracking Bug
@JvmField
- val SPLIT_SHADE_SUBPIXEL_OPTIMIZATION = releasedFlag("split_shade_subpixel_optimization")
+ val SPLIT_SHADE_SUBPIXEL_OPTIMIZATION = unreleasedFlag("split_shade_subpixel_optimization")
// TODO(b/288868056): Tracking Bug
@JvmField
@@ -707,7 +703,7 @@
/** Enable showing a dialog when clicking on Quick Settings bluetooth tile. */
@JvmField
- val BLUETOOTH_QS_TILE_DIALOG = unreleasedFlag("bluetooth_qs_tile_dialog")
+ val BLUETOOTH_QS_TILE_DIALOG = releasedFlag("bluetooth_qs_tile_dialog")
// TODO(b/300995746): Tracking Bug
/** A resource flag for whether the communal service is enabled. */
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index fe9865b..53ec3de 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -3401,7 +3401,7 @@
}
if (mPowerGestureIntercepted && mOccluded && isSecure()
- && mUpdateMonitor.isFaceEnrolled()) {
+ && mUpdateMonitor.isFaceEnabledAndEnrolled()) {
flags |= StatusBarManager.DISABLE_RECENT;
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt
index c4dfe9a..8ef2662 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt
@@ -69,7 +69,6 @@
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
-import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.filterNotNull
@@ -89,7 +88,7 @@
*/
interface DeviceEntryFaceAuthRepository {
/** Provide the current face authentication state for device entry. */
- val isAuthenticated: Flow<Boolean>
+ val isAuthenticated: StateFlow<Boolean>
/** Whether face auth can run at this point. */
val canRunFaceAuth: StateFlow<Boolean>
@@ -199,8 +198,7 @@
private val canRunDetection: StateFlow<Boolean>
private val _isAuthenticated = MutableStateFlow(false)
- override val isAuthenticated: Flow<Boolean>
- get() = _isAuthenticated
+ override val isAuthenticated: StateFlow<Boolean> = _isAuthenticated
private var cancellationInProgress = MutableStateFlow(false)
@@ -243,61 +241,52 @@
.collect(Collectors.toSet())
dumpManager.registerCriticalDumpable("DeviceEntryFaceAuthRepositoryImpl", this)
- if (featureFlags.isEnabled(Flags.FACE_AUTH_REFACTOR)) {
- canRunFaceAuth =
- listOf(
- *gatingConditionsForAuthAndDetect(),
- Pair(isLockedOut.isFalse(), "isNotInLockOutState"),
- Pair(
- trustRepository.isCurrentUserTrusted.isFalse(),
- "currentUserIsNotTrusted"
- ),
- Pair(
- biometricSettingsRepository.isFaceAuthCurrentlyAllowed,
- "isFaceAuthCurrentlyAllowed"
- ),
- Pair(isAuthenticated.isFalse(), "faceNotAuthenticated"),
- )
- .andAllFlows("canFaceAuthRun", faceAuthLog)
- .flowOn(mainDispatcher)
- .stateIn(applicationScope, SharingStarted.Eagerly, false)
+ canRunFaceAuth =
+ listOf(
+ *gatingConditionsForAuthAndDetect(),
+ Pair(isLockedOut.isFalse(), "isNotInLockOutState"),
+ Pair(trustRepository.isCurrentUserTrusted.isFalse(), "currentUserIsNotTrusted"),
+ Pair(
+ biometricSettingsRepository.isFaceAuthCurrentlyAllowed,
+ "isFaceAuthCurrentlyAllowed"
+ ),
+ Pair(isAuthenticated.isFalse(), "faceNotAuthenticated"),
+ )
+ .andAllFlows("canFaceAuthRun", faceAuthLog)
+ .flowOn(mainDispatcher)
+ .stateIn(applicationScope, SharingStarted.Eagerly, false)
- // Face detection can run only when lockscreen bypass is enabled
- // & detection is supported
- // & biometric unlock is not allowed
- // or user is trusted by trust manager & we want to run face detect to dismiss
- // keyguard
- canRunDetection =
- listOf(
- *gatingConditionsForAuthAndDetect(),
- Pair(isBypassEnabled, "isBypassEnabled"),
- Pair(
- biometricSettingsRepository.isFaceAuthCurrentlyAllowed
- .isFalse()
- .or(trustRepository.isCurrentUserTrusted),
- "faceAuthIsNotCurrentlyAllowedOrCurrentUserIsTrusted"
- ),
- // We don't want to run face detect if fingerprint can be used to unlock the
- // device
- // but it's not possible to authenticate with FP from the bouncer (UDFPS)
- Pair(
- and(isUdfps(), deviceEntryFingerprintAuthRepository.isRunning)
- .isFalse(),
- "udfpsAuthIsNotPossibleAnymore"
- )
+ // Face detection can run only when lockscreen bypass is enabled
+ // & detection is supported
+ // & biometric unlock is not allowed
+ // or user is trusted by trust manager & we want to run face detect to dismiss
+ // keyguard
+ canRunDetection =
+ listOf(
+ *gatingConditionsForAuthAndDetect(),
+ Pair(isBypassEnabled, "isBypassEnabled"),
+ Pair(
+ biometricSettingsRepository.isFaceAuthCurrentlyAllowed
+ .isFalse()
+ .or(trustRepository.isCurrentUserTrusted),
+ "faceAuthIsNotCurrentlyAllowedOrCurrentUserIsTrusted"
+ ),
+ // We don't want to run face detect if fingerprint can be used to unlock the
+ // device
+ // but it's not possible to authenticate with FP from the bouncer (UDFPS)
+ Pair(
+ and(isUdfps(), deviceEntryFingerprintAuthRepository.isRunning).isFalse(),
+ "udfpsAuthIsNotPossibleAnymore"
)
- .andAllFlows("canFaceDetectRun", faceDetectLog)
- .flowOn(mainDispatcher)
- .stateIn(applicationScope, SharingStarted.Eagerly, false)
- observeFaceAuthGatingChecks()
- observeFaceDetectGatingChecks()
- observeFaceAuthResettingConditions()
- listenForSchedulingWatchdog()
- processPendingAuthRequests()
- } else {
- canRunFaceAuth = MutableStateFlow(false).asStateFlow()
- canRunDetection = MutableStateFlow(false).asStateFlow()
- }
+ )
+ .andAllFlows("canFaceDetectRun", faceDetectLog)
+ .flowOn(mainDispatcher)
+ .stateIn(applicationScope, SharingStarted.Eagerly, false)
+ observeFaceAuthGatingChecks()
+ observeFaceDetectGatingChecks()
+ observeFaceAuthResettingConditions()
+ listenForSchedulingWatchdog()
+ processPendingAuthRequests()
}
private fun listenForSchedulingWatchdog() {
@@ -454,8 +443,8 @@
if (errorStatus.isLockoutError()) {
_isLockedOut.value = true
}
- _authenticationStatus.value = errorStatus
_isAuthenticated.value = false
+ _authenticationStatus.value = errorStatus
if (errorStatus.isHardwareError()) {
faceAuthLogger.hardwareError(errorStatus)
handleFaceHardwareError()
@@ -477,8 +466,17 @@
}
override fun onAuthenticationSucceeded(result: FaceManager.AuthenticationResult) {
- _authenticationStatus.value = SuccessFaceAuthenticationStatus(result)
+ // Update _isAuthenticated before _authenticationStatus is updated. There are
+ // consumers that receive the face authentication updates through a long chain of
+ // callbacks
+ // _authenticationStatus -> KeyguardUpdateMonitor -> KeyguardStateController ->
+ // onUnlockChanged
+ // These consumers then query the isAuthenticated boolean. This makes sure that the
+ // boolean is updated to new value before the event is propagated.
+ // TODO (b/310592822): once all consumers can use the new system directly, we don't
+ // have to worry about this ordering.
_isAuthenticated.value = true
+ _authenticationStatus.value = SuccessFaceAuthenticationStatus(result)
faceAuthLogger.faceAuthSuccess(result)
onFaceAuthRequestCompleted()
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/NoopDeviceEntryFaceAuthRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/NoopDeviceEntryFaceAuthRepository.kt
index c8cb9e6..f4a74f0 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/NoopDeviceEntryFaceAuthRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/NoopDeviceEntryFaceAuthRepository.kt
@@ -24,6 +24,7 @@
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.emptyFlow
/**
@@ -34,11 +35,9 @@
*/
@SysUISingleton
class NoopDeviceEntryFaceAuthRepository @Inject constructor() : DeviceEntryFaceAuthRepository {
- override val isAuthenticated: Flow<Boolean>
- get() = emptyFlow()
+ override val isAuthenticated: StateFlow<Boolean> = MutableStateFlow(false)
- private val _canRunFaceAuth = MutableStateFlow(false)
- override val canRunFaceAuth: StateFlow<Boolean> = _canRunFaceAuth
+ override val canRunFaceAuth: StateFlow<Boolean> = MutableStateFlow(false)
override val authenticationStatus: Flow<FaceAuthenticationStatus>
get() = emptyFlow()
@@ -46,11 +45,9 @@
override val detectionStatus: Flow<FaceDetectionStatus>
get() = emptyFlow()
- private val _isLockedOut = MutableStateFlow(false)
- override val isLockedOut: StateFlow<Boolean> = _isLockedOut
+ override val isLockedOut: StateFlow<Boolean> = MutableStateFlow(false).asStateFlow()
- private val _isAuthRunning = MutableStateFlow(false)
- override val isAuthRunning: StateFlow<Boolean> = _isAuthRunning
+ override val isAuthRunning: StateFlow<Boolean> = MutableStateFlow(false).asStateFlow()
override val isBypassEnabled: Flow<Boolean>
get() = emptyFlow()
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractor.kt
index 85b0f4fb..5ed70b5 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractor.kt
@@ -44,6 +44,8 @@
/** Whether face auth is enrolled and enabled for the current user */
fun isFaceAuthEnabledAndEnrolled(): Boolean
+ /** Whether the current user is authenticated successfully with face auth */
+ fun isAuthenticated(): Boolean
/**
* Register listener for use from code that cannot use [authenticationStatus] or
* [detectionStatus]
@@ -53,9 +55,6 @@
/** Unregister previously registered listener */
fun unregisterListener(listener: FaceAuthenticationListener)
- /** Whether the face auth interactor is enabled or not. */
- fun isEnabled(): Boolean
-
fun onUdfpsSensorTouched()
fun onAssistantTriggeredOnLockScreen()
fun onDeviceLifted()
@@ -65,6 +64,9 @@
fun onPrimaryBouncerUserInput()
fun onAccessibilityAction()
fun onWalletLaunched()
+
+ /** Whether face auth is considered class 3 */
+ fun isFaceAuthStrong(): Boolean
}
/**
@@ -81,4 +83,10 @@
/** Receive status updates whenever face detection runs */
fun onDetectionStatusChanged(status: FaceDetectionStatus)
+
+ fun onLockoutStateChanged(isLockedOut: Boolean)
+
+ fun onRunningStateChanged(isRunning: Boolean)
+
+ fun onAuthEnrollmentStateChanged(enrolled: Boolean)
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
index 949c940..91b6715 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
@@ -31,8 +31,6 @@
import com.android.systemui.common.shared.model.SharedNotificationContainerPosition
import com.android.systemui.common.ui.data.repository.ConfigurationRepository
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.flags.FeatureFlags
-import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.data.repository.KeyguardRepository
import com.android.systemui.keyguard.shared.model.BiometricUnlockModel
import com.android.systemui.keyguard.shared.model.CameraLaunchSourceModel
@@ -76,8 +74,7 @@
constructor(
private val repository: KeyguardRepository,
private val commandQueue: CommandQueue,
- private val powerInteractor: PowerInteractor,
- featureFlags: FeatureFlags,
+ powerInteractor: PowerInteractor,
sceneContainerFlags: SceneContainerFlags,
bouncerRepository: KeyguardBouncerRepository,
configurationRepository: ConfigurationRepository,
@@ -197,22 +194,18 @@
/** Whether camera is launched over keyguard. */
val isSecureCameraActive: Flow<Boolean> by lazy {
- if (featureFlags.isEnabled(Flags.FACE_AUTH_REFACTOR)) {
- combine(
- isKeyguardVisible,
- primaryBouncerShowing,
- onCameraLaunchDetected,
- ) { isKeyguardVisible, isPrimaryBouncerShowing, cameraLaunchEvent ->
- when {
- isKeyguardVisible -> false
- isPrimaryBouncerShowing -> false
- else -> cameraLaunchEvent == CameraLaunchSourceModel.POWER_DOUBLE_TAP
- }
+ combine(
+ isKeyguardVisible,
+ primaryBouncerShowing,
+ onCameraLaunchDetected,
+ ) { isKeyguardVisible, isPrimaryBouncerShowing, cameraLaunchEvent ->
+ when {
+ isKeyguardVisible -> false
+ isPrimaryBouncerShowing -> false
+ else -> cameraLaunchEvent == CameraLaunchSourceModel.POWER_DOUBLE_TAP
}
- .onStart { emit(false) }
- } else {
- flowOf(false)
- }
+ }
+ .onStart { emit(false) }
}
/** The approximate location on the screen of the fingerprint sensor, if one is available. */
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/NoopKeyguardFaceAuthInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/NoopKeyguardFaceAuthInteractor.kt
index fbadde6..cd6ab31 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/NoopKeyguardFaceAuthInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/NoopKeyguardFaceAuthInteractor.kt
@@ -42,9 +42,12 @@
override fun isLockedOut(): Boolean = false
- override fun isEnabled() = false
override fun isFaceAuthEnabledAndEnrolled(): Boolean = false
+ override fun isFaceAuthStrong(): Boolean = false
+
+ override fun isAuthenticated(): Boolean = false
+
override fun registerListener(listener: FaceAuthenticationListener) {}
override fun unregisterListener(listener: FaceAuthenticationListener) {}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/SystemUIKeyguardFaceAuthInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/SystemUIKeyguardFaceAuthInteractor.kt
index 2641846..ae356cd 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/SystemUIKeyguardFaceAuthInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/SystemUIKeyguardFaceAuthInteractor.kt
@@ -30,8 +30,6 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Main
-import com.android.systemui.flags.FeatureFlags
-import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.data.repository.BiometricSettingsRepository
import com.android.systemui.keyguard.data.repository.DeviceEntryFaceAuthRepository
import com.android.systemui.keyguard.data.repository.DeviceEntryFingerprintAuthRepository
@@ -45,6 +43,7 @@
import com.android.systemui.user.data.repository.UserRepository
import com.android.systemui.util.kotlin.pairwise
import com.android.systemui.util.kotlin.sample
+import dagger.Lazy
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
@@ -71,10 +70,9 @@
@Application private val applicationScope: CoroutineScope,
@Main private val mainDispatcher: CoroutineDispatcher,
private val repository: DeviceEntryFaceAuthRepository,
- private val primaryBouncerInteractor: PrimaryBouncerInteractor,
+ private val primaryBouncerInteractor: Lazy<PrimaryBouncerInteractor>,
private val alternateBouncerInteractor: AlternateBouncerInteractor,
private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
- private val featureFlags: FeatureFlags,
private val faceAuthenticationLogger: FaceAuthenticationLogger,
private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
private val deviceEntryFingerprintAuthRepository: DeviceEntryFingerprintAuthRepository,
@@ -88,16 +86,16 @@
private val listeners: MutableList<FaceAuthenticationListener> = mutableListOf()
override fun start() {
- if (!isEnabled()) {
- return
- }
- // This is required because fingerprint state required for the face auth repository is
- // backed by KeyguardUpdateMonitor. KeyguardUpdateMonitor constructor accesses the biometric
- // state which makes lazy injection not an option.
+ // Todo(b/310594096): there is a dependency cycle introduced by the repository depending on
+ // KeyguardBypassController, which in turn depends on KeyguardUpdateMonitor through
+ // its other dependencies. Once bypassEnabled state is available through a repository, we
+ // can break that cycle and inject this interactor directly into KeyguardUpdateMonitor
keyguardUpdateMonitor.setFaceAuthInteractor(this)
observeFaceAuthStateUpdates()
faceAuthenticationLogger.interactorStarted()
- primaryBouncerInteractor.isShowing
+ primaryBouncerInteractor
+ .get()
+ .isShowing
.whenItFlipsToTrue()
.onEach {
faceAuthenticationLogger.bouncerVisibilityChanged()
@@ -176,7 +174,7 @@
FaceAuthUiEvent.FACE_AUTH_UPDATED_USER_SWITCHING,
// Fallback to detection if bouncer is not showing so that we can detect a
// face and then show the bouncer to the user if face auth can't run
- fallbackToDetect = !primaryBouncerInteractor.isBouncerShowing()
+ fallbackToDetect = !primaryBouncerInteractor.get().isBouncerShowing()
)
}
}
@@ -231,9 +229,8 @@
override fun canFaceAuthRun(): Boolean = repository.canRunFaceAuth.value
- override fun isEnabled(): Boolean {
- return featureFlags.isEnabled(Flags.FACE_AUTH_REFACTOR)
- }
+ override fun isFaceAuthStrong(): Boolean =
+ facePropertyRepository.sensorInfo.value?.strength == SensorStrength.STRONG
override fun onPrimaryBouncerUserInput() {
repository.cancel()
@@ -248,29 +245,24 @@
override val detectionStatus = repository.detectionStatus
private fun runFaceAuth(uiEvent: FaceAuthUiEvent, fallbackToDetect: Boolean) {
- if (featureFlags.isEnabled(Flags.FACE_AUTH_REFACTOR)) {
- if (repository.isLockedOut.value) {
- faceAuthenticationStatusOverride.value =
- ErrorFaceAuthenticationStatus(
- BiometricFaceConstants.FACE_ERROR_LOCKOUT_PERMANENT,
- context.resources.getString(R.string.keyguard_face_unlock_unavailable)
- )
- } else {
- faceAuthenticationStatusOverride.value = null
- faceAuthenticationLogger.authRequested(uiEvent)
- repository.requestAuthenticate(uiEvent, fallbackToDetection = fallbackToDetect)
- }
+ if (repository.isLockedOut.value) {
+ faceAuthenticationStatusOverride.value =
+ ErrorFaceAuthenticationStatus(
+ BiometricFaceConstants.FACE_ERROR_LOCKOUT_PERMANENT,
+ context.resources.getString(R.string.keyguard_face_unlock_unavailable)
+ )
} else {
- faceAuthenticationLogger.ignoredFaceAuthTrigger(
- uiEvent,
- ignoredReason = "Skipping face auth request because feature flag is false"
- )
+ faceAuthenticationStatusOverride.value = null
+ faceAuthenticationLogger.authRequested(uiEvent)
+ repository.requestAuthenticate(uiEvent, fallbackToDetection = fallbackToDetect)
}
}
override fun isFaceAuthEnabledAndEnrolled(): Boolean =
biometricSettingsRepository.isFaceAuthEnrolledAndEnabled.value
+ override fun isAuthenticated(): Boolean = repository.isAuthenticated.value
+
private fun observeFaceAuthStateUpdates() {
authenticationStatus
.onEach { authStatusUpdate ->
@@ -284,6 +276,21 @@
}
.flowOn(mainDispatcher)
.launchIn(applicationScope)
+ repository.isLockedOut
+ .onEach { lockedOut -> listeners.forEach { it.onLockoutStateChanged(lockedOut) } }
+ .flowOn(mainDispatcher)
+ .launchIn(applicationScope)
+ repository.isAuthRunning
+ .onEach { running -> listeners.forEach { it.onRunningStateChanged(running) } }
+ .flowOn(mainDispatcher)
+ .launchIn(applicationScope)
+
+ biometricSettingsRepository.isFaceAuthEnrolledAndEnabled
+ .onEach { enrolledAndEnabled ->
+ listeners.forEach { it.onAuthEnrollmentStateChanged(enrolledAndEnabled) }
+ }
+ .flowOn(mainDispatcher)
+ .launchIn(applicationScope)
}
companion object {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/SwipeUpAnywhereGestureHandler.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/SwipeUpAnywhereGestureHandler.kt
new file mode 100644
index 0000000..3540a0c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/SwipeUpAnywhereGestureHandler.kt
@@ -0,0 +1,45 @@
+/*
+ * 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.systemui.keyguard.ui
+
+import android.content.Context
+import android.view.MotionEvent
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.settings.DisplayTracker
+import com.android.systemui.statusbar.gesture.SwipeUpGestureHandler
+import com.android.systemui.statusbar.gesture.SwipeUpGestureLogger
+import javax.inject.Inject
+
+/** A class to detect when a user swipes up anywhere on the display. */
+@SysUISingleton
+class SwipeUpAnywhereGestureHandler
+@Inject
+constructor(
+ context: Context,
+ displayTracker: DisplayTracker,
+ logger: SwipeUpGestureLogger,
+) :
+ SwipeUpGestureHandler(
+ context,
+ displayTracker,
+ logger,
+ loggerTag = "SwipeUpAnywhereGestureHandler"
+ ) {
+ override fun startOfGestureIsWithinBounds(ev: MotionEvent): Boolean {
+ return true
+ }
+}
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 a6383eb..594865d3 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
@@ -20,23 +20,21 @@
import android.view.ViewGroup
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
+import com.android.systemui.classifier.Classifier
import com.android.systemui.deviceentry.shared.DeviceEntryUdfpsRefactor
+import com.android.systemui.keyguard.ui.SwipeUpAnywhereGestureHandler
import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerViewModel
import com.android.systemui.lifecycle.repeatWhenAttached
+import com.android.systemui.plugins.FalsingManager
import com.android.systemui.res.R
import com.android.systemui.scrim.ScrimView
import com.android.systemui.statusbar.NotificationShadeWindowController
+import com.android.systemui.statusbar.gesture.TapGestureDetector
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.launch
-/**
- * Binds the alternate bouncer view to its view-model.
- *
- * To use this properly, users should maintain a one-to-one relationship between the [View] and the
- * view-binding, binding each view only once. It is okay and expected for the same instance of the
- * view-model to be reused for multiple view/view-binder bindings.
- */
+/** Binds the alternate bouncer view to its view-model. */
@ExperimentalCoroutinesApi
object AlternateBouncerViewBinder {
@@ -47,6 +45,9 @@
viewModel: AlternateBouncerViewModel,
scope: CoroutineScope,
notificationShadeWindowController: NotificationShadeWindowController,
+ falsingManager: FalsingManager,
+ swipeUpAnywhereGestureHandler: SwipeUpAnywhereGestureHandler,
+ tapGestureDetector: TapGestureDetector,
) {
DeviceEntryUdfpsRefactor.isUnexpectedlyInLegacyMode()
scope.launch {
@@ -64,9 +65,25 @@
scrim.viewAlpha = 0f
launch {
- viewModel.onClickListener.collect {
- // TODO (b/287599719): Support swiping to dismiss altBouncer
- alternateBouncerViewContainer.setOnClickListener(it)
+ viewModel.registerForDismissGestures.collect { registerForDismissGestures ->
+ if (registerForDismissGestures) {
+ swipeUpAnywhereGestureHandler.addOnGestureDetectedCallback(swipeTag) { _
+ ->
+ if (
+ !falsingManager.isFalseTouch(Classifier.ALTERNATE_BOUNCER_SWIPE)
+ ) {
+ viewModel.showPrimaryBouncer()
+ }
+ }
+ tapGestureDetector.addOnGestureDetectedCallback(tapTag) { _ ->
+ if (!falsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
+ viewModel.showPrimaryBouncer()
+ }
+ }
+ } else {
+ swipeUpAnywhereGestureHandler.removeOnGestureDetectedCallback(swipeTag)
+ tapGestureDetector.removeOnGestureDetectedCallback(tapTag)
+ }
}
}
@@ -83,3 +100,6 @@
}
}
}
+
+private const val swipeTag = "AlternateBouncer-SWIPE"
+private const val tapTag = "AlternateBouncer-TAP"
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprint.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprint.kt
index 27b38c7..fa27442 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprint.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprint.kt
@@ -24,7 +24,7 @@
import com.android.systemui.keyguard.ui.view.layout.items.ClockSection
import com.android.systemui.keyguard.ui.view.layout.sections.AodBurnInSection
import com.android.systemui.keyguard.ui.view.layout.sections.AodNotificationIconsSection
-import com.android.systemui.keyguard.ui.view.layout.sections.DefaultDeviceEntryIconSection
+import com.android.systemui.keyguard.ui.view.layout.sections.DefaultDeviceEntrySection
import com.android.systemui.keyguard.ui.view.layout.sections.DefaultIndicationAreaSection
import com.android.systemui.keyguard.ui.view.layout.sections.DefaultNotificationStackScrollLayoutSection
import com.android.systemui.keyguard.ui.view.layout.sections.DefaultSettingsPopupMenuSection
@@ -49,7 +49,7 @@
@Inject
constructor(
defaultIndicationAreaSection: DefaultIndicationAreaSection,
- defaultDeviceEntryIconSection: DefaultDeviceEntryIconSection,
+ defaultDeviceEntrySection: DefaultDeviceEntrySection,
defaultShortcutsSection: DefaultShortcutsSection,
@Named(KEYGUARD_AMBIENT_INDICATION_AREA_SECTION)
defaultAmbientIndicationAreaSection: Optional<KeyguardSection>,
@@ -79,7 +79,7 @@
communalTutorialIndicatorSection,
clockSection,
smartspaceSection,
- defaultDeviceEntryIconSection, // Add LAST: Intentionally has z-order above other views.
+ defaultDeviceEntrySection, // Add LAST: Intentionally has z-order above other views.
)
companion object {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/ShortcutsBesideUdfpsKeyguardBlueprint.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/ShortcutsBesideUdfpsKeyguardBlueprint.kt
index 190ad44..bf70682 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/ShortcutsBesideUdfpsKeyguardBlueprint.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/ShortcutsBesideUdfpsKeyguardBlueprint.kt
@@ -23,7 +23,7 @@
import com.android.systemui.keyguard.ui.view.layout.sections.AlignShortcutsToUdfpsSection
import com.android.systemui.keyguard.ui.view.layout.sections.AodBurnInSection
import com.android.systemui.keyguard.ui.view.layout.sections.AodNotificationIconsSection
-import com.android.systemui.keyguard.ui.view.layout.sections.DefaultDeviceEntryIconSection
+import com.android.systemui.keyguard.ui.view.layout.sections.DefaultDeviceEntrySection
import com.android.systemui.keyguard.ui.view.layout.sections.DefaultIndicationAreaSection
import com.android.systemui.keyguard.ui.view.layout.sections.DefaultNotificationStackScrollLayoutSection
import com.android.systemui.keyguard.ui.view.layout.sections.DefaultSettingsPopupMenuSection
@@ -42,7 +42,7 @@
@Inject
constructor(
defaultIndicationAreaSection: DefaultIndicationAreaSection,
- defaultDeviceEntryIconSection: DefaultDeviceEntryIconSection,
+ defaultDeviceEntrySection: DefaultDeviceEntrySection,
@Named(KeyguardSectionsModule.KEYGUARD_AMBIENT_INDICATION_AREA_SECTION)
defaultAmbientIndicationAreaSection: Optional<KeyguardSection>,
defaultSettingsPopupMenuSection: DefaultSettingsPopupMenuSection,
@@ -68,7 +68,7 @@
splitShadeGuidelines,
aodNotificationIconsSection,
aodBurnInSection,
- defaultDeviceEntryIconSection, // Add LAST: Intentionally has z-order above other views.
+ defaultDeviceEntrySection, // Add LAST: Intentionally has z-order above other views.
)
companion object {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/SplitShadeKeyguardBlueprint.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/SplitShadeKeyguardBlueprint.kt
index acbcf27..f890ae6 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/SplitShadeKeyguardBlueprint.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/SplitShadeKeyguardBlueprint.kt
@@ -23,7 +23,7 @@
import com.android.systemui.keyguard.shared.model.KeyguardSection
import com.android.systemui.keyguard.ui.view.layout.sections.AodBurnInSection
import com.android.systemui.keyguard.ui.view.layout.sections.AodNotificationIconsSection
-import com.android.systemui.keyguard.ui.view.layout.sections.DefaultDeviceEntryIconSection
+import com.android.systemui.keyguard.ui.view.layout.sections.DefaultDeviceEntrySection
import com.android.systemui.keyguard.ui.view.layout.sections.DefaultIndicationAreaSection
import com.android.systemui.keyguard.ui.view.layout.sections.DefaultSettingsPopupMenuSection
import com.android.systemui.keyguard.ui.view.layout.sections.DefaultShortcutsSection
@@ -47,7 +47,7 @@
@Inject
constructor(
defaultIndicationAreaSection: DefaultIndicationAreaSection,
- defaultDeviceEntryIconSection: DefaultDeviceEntryIconSection,
+ defaultDeviceEntrySection: DefaultDeviceEntrySection,
defaultShortcutsSection: DefaultShortcutsSection,
@Named(KeyguardSectionsModule.KEYGUARD_AMBIENT_INDICATION_AREA_SECTION)
defaultAmbientIndicationAreaSection: Optional<KeyguardSection>,
@@ -75,7 +75,7 @@
aodNotificationIconsSection,
aodBurnInSection,
communalTutorialIndicatorSection,
- defaultDeviceEntryIconSection, // Add LAST: Intentionally has z-order above other views.
+ defaultDeviceEntrySection, // Add LAST: Intentionally has z-order above other views.
)
companion object {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntryIconSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySection.kt
similarity index 94%
rename from packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntryIconSection.kt
rename to packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySection.kt
index fac8498..77ab9f4 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntryIconSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySection.kt
@@ -37,6 +37,7 @@
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.shared.model.KeyguardSection
+import com.android.systemui.keyguard.ui.SwipeUpAnywhereGestureHandler
import com.android.systemui.keyguard.ui.binder.AlternateBouncerViewBinder
import com.android.systemui.keyguard.ui.binder.DeviceEntryIconViewBinder
import com.android.systemui.keyguard.ui.view.DeviceEntryIconView
@@ -48,6 +49,7 @@
import com.android.systemui.res.R
import com.android.systemui.shade.NotificationPanelView
import com.android.systemui.statusbar.NotificationShadeWindowController
+import com.android.systemui.statusbar.gesture.TapGestureDetector
import dagger.Lazy
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
@@ -55,7 +57,7 @@
/** Includes both the device entry icon and the alternate bouncer scrim. */
@ExperimentalCoroutinesApi
-class DefaultDeviceEntryIconSection
+class DefaultDeviceEntrySection
@Inject
constructor(
private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
@@ -72,6 +74,8 @@
private val alternateBouncerViewModel: Lazy<AlternateBouncerViewModel>,
private val notificationShadeWindowController: Lazy<NotificationShadeWindowController>,
@Application private val scope: CoroutineScope,
+ private val swipeUpAnywhereGestureHandler: Lazy<SwipeUpAnywhereGestureHandler>,
+ private val tapGestureDetector: Lazy<TapGestureDetector>,
) : KeyguardSection() {
private val deviceEntryIconViewId = R.id.device_entry_icon_view
private val alternateBouncerViewId = R.id.alternate_bouncer
@@ -118,6 +122,9 @@
alternateBouncerViewModel.get(),
scope,
notificationShadeWindowController.get(),
+ falsingManager.get(),
+ swipeUpAnywhereGestureHandler.get(),
+ tapGestureDetector.get(),
)
}
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerViewModel.kt
index 235a28d..bb7bcd9 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerViewModel.kt
@@ -18,12 +18,10 @@
package com.android.systemui.keyguard.ui.viewmodel
import android.graphics.Color
-import android.view.View
import com.android.systemui.keyguard.domain.interactor.FromAlternateBouncerTransitionInteractor.Companion.TRANSITION_DURATION_MS
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.shared.model.KeyguardState.ALTERNATE_BOUNCER
import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
-import com.android.systemui.plugins.FalsingManager
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
import com.android.wm.shell.animation.Interpolators
import javax.inject.Inject
@@ -38,9 +36,8 @@
class AlternateBouncerViewModel
@Inject
constructor(
- statusBarKeyguardViewManager: StatusBarKeyguardViewManager,
+ private val statusBarKeyguardViewManager: StatusBarKeyguardViewManager,
transitionInteractor: KeyguardTransitionInteractor,
- falsingManager: FalsingManager,
) {
// When we're fully transitioned to the AlternateBouncer, the alpha of the scrim should be:
private val alternateBouncerScrimAlpha = .66f
@@ -83,21 +80,10 @@
/** An observable for the scrim color. Change color for easier debugging. */
val scrimColor: Flow<Int> = flowOf(Color.BLACK)
- private val clickListener =
- View.OnClickListener {
- if (!falsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
- statusBarKeyguardViewManager.showPrimaryBouncer(/* scrimmed */ true)
- }
- }
+ val registerForDismissGestures: Flow<Boolean> =
+ transitionToAlternateBouncerProgress.map { it == 1f }.distinctUntilChanged()
- val onClickListener: Flow<View.OnClickListener?> =
- transitionToAlternateBouncerProgress
- .map {
- if (it == 1f) {
- clickListener
- } else {
- null
- }
- }
- .distinctUntilChanged()
+ fun showPrimaryBouncer() {
+ statusBarKeyguardViewManager.showPrimaryBouncer(/* scrimmed */ true)
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt
index 315626b..b3c7d379 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt
@@ -25,7 +25,6 @@
import com.android.systemui.common.shared.model.SharedNotificationContainerPosition
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor
-import com.android.systemui.flags.FeatureFlagsClassic
import com.android.systemui.keyguard.domain.interactor.BurnInInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
@@ -67,7 +66,6 @@
private val context: Context,
private val deviceEntryInteractor: DeviceEntryInteractor,
private val dozeParameters: DozeParameters,
- private val featureFlags: FeatureFlagsClassic,
private val keyguardInteractor: KeyguardInteractor,
private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
private val notificationsKeyguardInteractor: NotificationsKeyguardInteractor,
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index c810786..c06e9a4 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -98,7 +98,6 @@
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.util.LatencyTracker;
import com.android.keyguard.ActiveUnlockConfig;
-import com.android.keyguard.FaceAuthApiRequestReason;
import com.android.keyguard.KeyguardClockSwitch.ClockSize;
import com.android.keyguard.KeyguardStatusView;
import com.android.keyguard.KeyguardStatusViewController;
@@ -2966,10 +2965,8 @@
// Try triggering face auth, this "might" run. Check
// KeyguardUpdateMonitor#shouldListenForFace to see when face auth won't run.
mKeyguardFaceAuthInteractor.onNotificationPanelClicked();
- boolean didFaceAuthRun = mUpdateMonitor.requestFaceAuth(
- FaceAuthApiRequestReason.NOTIFICATION_PANEL_CLICKED);
- if (didFaceAuthRun) {
+ if (mKeyguardFaceAuthInteractor.canFaceAuthRun()) {
mUpdateMonitor.requestActiveUnlock(
ActiveUnlockConfig.ActiveUnlockRequestOrigin.UNLOCK_INTENT,
"lockScreenEmptySpaceTap");
diff --git a/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java b/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java
index e84bfc5..dd194eaa 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java
@@ -61,7 +61,6 @@
import com.android.internal.logging.nano.MetricsProto;
import com.android.internal.policy.ScreenDecorationsUtils;
import com.android.internal.policy.SystemBarUtils;
-import com.android.keyguard.FaceAuthApiRequestReason;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.DejankUtils;
import com.android.systemui.Dumpable;
@@ -981,7 +980,6 @@
// this will speed up notification actions.
if (height == 0 && !mKeyguardStateController.canDismissLockScreen()) {
mKeyguardFaceAuthInteractor.onQsExpansionStared();
- mKeyguardUpdateMonitor.requestFaceAuth(FaceAuthApiRequestReason.QS_EXPANDED);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index dd24ca7..08415cb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -1033,7 +1033,7 @@
if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
if (mAlternateBouncerInteractor.isVisibleState()) {
return; // udfps affordance is highlighted, no need to show action to unlock
- } else if (mKeyguardUpdateMonitor.isFaceEnrolled()
+ } else if (mKeyguardUpdateMonitor.isFaceEnabledAndEnrolled()
&& !mKeyguardUpdateMonitor.getIsFaceAuthenticated()) {
String message;
if (mAccessibilityManager.isEnabled()
@@ -1215,7 +1215,7 @@
mContext.getString(R.string.keyguard_suggest_fingerprint)
);
} else if (fpAuthFailed
- && mKeyguardUpdateMonitor.getUserUnlockedWithFace(getCurrentUser())) {
+ && mKeyguardUpdateMonitor.isCurrentUserUnlockedWithFace()) {
// face had already previously unlocked the device, so instead of showing a
// fingerprint error, tell them they have already unlocked with face auth
// and how to enter their device
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/data/model/StatusBarMode.kt b/packages/SystemUI/src/com/android/systemui/statusbar/data/model/StatusBarMode.kt
index 747efe3..933d0ab 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/data/model/StatusBarMode.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/data/model/StatusBarMode.kt
@@ -36,7 +36,8 @@
/**
* A mode where notification icons in the status bar are hidden and replaced by a dot (this mode
* can be requested by apps). See
- * [com.android.systemui.statusbar.phone.LightsOutNotifController].
+ * [com.android.systemui.statusbar.phone.LegacyLightsOutNotifController] and
+ * [com.android.systemui.statusbar.phone.domain.interactor.LightsOutInteractor].
*/
LIGHTS_OUT,
/** Similar to [LIGHTS_OUT], but also with a transparent background for the status bar. */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/KeyguardStatusBarRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/KeyguardStatusBarRepository.kt
index d1594ef..0415212 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/KeyguardStatusBarRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/KeyguardStatusBarRepository.kt
@@ -33,7 +33,7 @@
/**
* Repository for data that's specific to the status bar **on keyguard**. For data that applies to
- * all status bars, use [StatusBarModeRepository].
+ * all status bars, use [StatusBarModeRepositoryStore].
*/
interface KeyguardStatusBarRepository {
/** True if we can show the user switcher on keyguard and false otherwise. */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarModeRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarModePerDisplayRepository.kt
similarity index 92%
rename from packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarModeRepository.kt
rename to packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarModePerDisplayRepository.kt
index 47994d9..6429815 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarModeRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarModePerDisplayRepository.kt
@@ -25,10 +25,8 @@
import android.view.WindowInsetsController.Appearance
import com.android.internal.statusbar.LetterboxDetails
import com.android.internal.view.AppearanceRegion
-import com.android.systemui.CoreStartable
-import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.Dumpable
import com.android.systemui.dagger.qualifiers.Application
-import com.android.systemui.dagger.qualifiers.DisplayId
import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.statusbar.core.StatusBarInitializer.OnStatusBarViewInitializedListener
import com.android.systemui.statusbar.data.model.StatusBarAppearance
@@ -38,13 +36,10 @@
import com.android.systemui.statusbar.phone.StatusBarBoundsProvider
import com.android.systemui.statusbar.phone.fragment.dagger.StatusBarFragmentComponent
import com.android.systemui.statusbar.phone.ongoingcall.data.repository.OngoingCallRepository
-import dagger.Binds
-import dagger.Module
-import dagger.multibindings.ClassKey
-import dagger.multibindings.IntoMap
-import dagger.multibindings.IntoSet
+import dagger.assisted.Assisted
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
import java.io.PrintWriter
-import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
@@ -61,7 +56,7 @@
* Note: These status bar modes are status bar *window* states that are sent to us from
* WindowManager, not determined internally.
*/
-interface StatusBarModeRepository {
+interface StatusBarModePerDisplayRepository {
/**
* True if the status bar window is showing transiently and will disappear soon, and false
* otherwise. ("Otherwise" in this case means the status bar is persistently hidden OR
@@ -108,16 +103,15 @@
fun clearTransient()
}
-@SysUISingleton
-class StatusBarModeRepositoryImpl
-@Inject
+class StatusBarModePerDisplayRepositoryImpl
+@AssistedInject
constructor(
@Application scope: CoroutineScope,
- @DisplayId thisDisplayId: Int,
+ @Assisted("displayId") thisDisplayId: Int,
private val commandQueue: CommandQueue,
private val letterboxAppearanceCalculator: LetterboxAppearanceCalculator,
ongoingCallRepository: OngoingCallRepository,
-) : StatusBarModeRepository, CoreStartable, OnStatusBarViewInitializedListener {
+) : StatusBarModePerDisplayRepository, OnStatusBarViewInitializedListener, Dumpable {
private val commandQueueCallback =
object : CommandQueue.Callbacks {
@@ -166,7 +160,7 @@
}
}
- override fun start() {
+ fun start() {
commandQueue.addCallback(commandQueueCallback)
}
@@ -340,16 +334,7 @@
)
}
-@Module
-interface StatusBarModeRepositoryModule {
- @Binds fun bindImpl(impl: StatusBarModeRepositoryImpl): StatusBarModeRepository
-
- @Binds
- @IntoMap
- @ClassKey(StatusBarModeRepositoryImpl::class)
- fun bindCoreStartable(impl: StatusBarModeRepositoryImpl): CoreStartable
-
- @Binds
- @IntoSet
- fun bindViewInitListener(impl: StatusBarModeRepositoryImpl): OnStatusBarViewInitializedListener
+@AssistedFactory
+interface StatusBarModePerDisplayRepositoryFactory {
+ fun create(@Assisted("displayId") displayId: Int): StatusBarModePerDisplayRepositoryImpl
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarModeRepositoryStore.kt b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarModeRepositoryStore.kt
new file mode 100644
index 0000000..962cb095
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarModeRepositoryStore.kt
@@ -0,0 +1,83 @@
+/*
+ * 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.systemui.statusbar.data.repository
+
+import com.android.systemui.CoreStartable
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.DisplayId
+import com.android.systemui.statusbar.core.StatusBarInitializer
+import com.android.systemui.statusbar.phone.fragment.dagger.StatusBarFragmentComponent
+import dagger.Binds
+import dagger.Module
+import dagger.multibindings.ClassKey
+import dagger.multibindings.IntoMap
+import dagger.multibindings.IntoSet
+import java.io.PrintWriter
+import javax.inject.Inject
+
+interface StatusBarModeRepositoryStore {
+ val defaultDisplay: StatusBarModePerDisplayRepository
+ fun forDisplay(displayId: Int): StatusBarModePerDisplayRepository
+}
+
+@SysUISingleton
+class StatusBarModeRepositoryImpl
+@Inject
+constructor(
+ @DisplayId private val displayId: Int,
+ factory: StatusBarModePerDisplayRepositoryFactory
+) :
+ StatusBarModeRepositoryStore,
+ CoreStartable,
+ StatusBarInitializer.OnStatusBarViewInitializedListener {
+ override val defaultDisplay = factory.create(displayId)
+
+ override fun forDisplay(displayId: Int) =
+ if (this.displayId == displayId) {
+ defaultDisplay
+ } else {
+ TODO("b/127878649 implement multi-display state management")
+ }
+
+ override fun start() {
+ defaultDisplay.start()
+ }
+
+ override fun onStatusBarViewInitialized(component: StatusBarFragmentComponent) {
+ defaultDisplay.onStatusBarViewInitialized(component)
+ }
+
+ override fun dump(pw: PrintWriter, args: Array<out String>) {
+ defaultDisplay.dump(pw, args)
+ }
+}
+
+@Module
+interface StatusBarModeRepositoryModule {
+ @Binds fun bindImpl(impl: StatusBarModeRepositoryImpl): StatusBarModeRepositoryStore
+
+ @Binds
+ @IntoMap
+ @ClassKey(StatusBarModeRepositoryStore::class)
+ fun bindCoreStartable(impl: StatusBarModeRepositoryImpl): CoreStartable
+
+ @Binds
+ @IntoSet
+ fun bindViewInitListener(
+ impl: StatusBarModeRepositoryImpl
+ ): StatusBarInitializer.OnStatusBarViewInitializedListener
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java
index 8eda96f..64f61d9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java
@@ -27,6 +27,7 @@
import android.graphics.drawable.LayerDrawable;
import android.graphics.drawable.RippleDrawable;
import android.util.AttributeSet;
+import android.util.Log;
import android.view.View;
import androidx.annotation.NonNull;
@@ -42,9 +43,11 @@
* A view that can be used for both the dimmed and normal background of an notification.
*/
public class NotificationBackgroundView extends View implements Dumpable {
+ private static final String TAG = "NotificationBackgroundView";
private final boolean mDontModifyCorners;
private Drawable mBackground;
+ private Drawable mBackgroundDrawableToTint;
private int mClipTopAmount;
private int mClipBottomAmount;
private int mTintColor;
@@ -131,6 +134,7 @@
unscheduleDrawable(mBackground);
}
mBackground = background;
+ mBackgroundDrawableToTint = findBackgroundDrawableToTint(mBackground);
mRippleColor = null;
mBackground.mutate();
if (mBackground != null) {
@@ -144,25 +148,46 @@
invalidate();
}
+ // setCustomBackground should be called from ActivatableNotificationView.initBackground
+ // with R.drawable.notification_material_bg, which is a layer-list with a lower layer
+ // for the background color (annotated with an ID so we can find it) and an upper layer
+ // to blend in the stateful @color/notification_overlay_color.
+ //
+ // If the notification is tinted, we want to set a tint list on *just that lower layer* that
+ // will replace the default materialColorSurfaceContainerHigh *without* wiping out the stateful
+ // tints in the upper layer that make the hovered and pressed states visible.
+ //
+ // This function fishes that lower layer out, or makes a fuss in logcat if it can't find it.
+ private @Nullable Drawable findBackgroundDrawableToTint(@Nullable Drawable background) {
+ if (background == null) {
+ return null;
+ }
+
+ if (!(background instanceof LayerDrawable)) {
+ Log.wtf(TAG, "background is not a LayerDrawable: " + background);
+ return background;
+ }
+
+ final Drawable backgroundColorLayer = ((LayerDrawable) background).findDrawableByLayerId(
+ R.id.notification_background_color_layer);
+
+ if (backgroundColorLayer == null) {
+ Log.wtf(TAG, "background is missing background color layer: " + background);
+ return background;
+ }
+
+ return backgroundColorLayer;
+ }
+
public void setCustomBackground(int drawableResId) {
final Drawable d = mContext.getDrawable(drawableResId);
setCustomBackground(d);
}
public void setTint(int tintColor) {
- if (tintColor != 0) {
- ColorStateList stateList = new ColorStateList(new int[][]{
- new int[]{com.android.internal.R.attr.state_pressed},
- new int[]{com.android.internal.R.attr.state_hovered},
- new int[]{}},
+ mBackgroundDrawableToTint.setTint(tintColor);
+ mBackgroundDrawableToTint.setTintMode(PorterDuff.Mode.SRC_ATOP);
- new int[]{tintColor, tintColor, tintColor}
- );
- mBackground.setTintMode(PorterDuff.Mode.SRC_ATOP);
- mBackground.setTintList(stateList);
- } else {
- mBackground.setTintList(null);
- }
mTintColor = tintColor;
invalidate();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/NotificationsLiveDataRefactor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/NotificationsLiveDataStoreRefactor.kt
similarity index 99%
rename from packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/NotificationsLiveDataRefactor.kt
rename to packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/NotificationsLiveDataStoreRefactor.kt
index 44387c2..8fc7106 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/NotificationsLiveDataRefactor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/NotificationsLiveDataStoreRefactor.kt
@@ -50,4 +50,4 @@
*/
@JvmStatic
inline fun assertInLegacyMode() = RefactorFlagUtils.assertInLegacyMode(isEnabled, FLAG_NAME)
-}
\ No newline at end of file
+}
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 61a79b7..6944453 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
@@ -565,6 +565,7 @@
private NotificationStackScrollLayoutController.TouchHandler mTouchHandler;
private final ScreenOffAnimationController mScreenOffAnimationController;
private boolean mShouldUseSplitNotificationShade;
+ private boolean mShouldSkipTopPaddingAnimationAfterFold = false;
private boolean mHasFilteredOutSeenNotifications;
@Nullable private SplitShadeStateController mSplitShadeStateController = null;
private boolean mIsSmallLandscapeLockscreenEnabled = false;
@@ -1364,7 +1365,11 @@
mTopPadding = topPadding;
updateAlgorithmHeightAndPadding();
updateContentHeight();
- if (shouldAnimate && mAnimationsEnabled && mIsExpanded) {
+ if (mAmbientState.isOnKeyguard()
+ && !mShouldUseSplitNotificationShade
+ && mShouldSkipTopPaddingAnimationAfterFold) {
+ mShouldSkipTopPaddingAnimationAfterFold = false;
+ } else if (shouldAnimate && mAnimationsEnabled && mIsExpanded) {
mTopPaddingNeedsAnimation = true;
mNeedsAnimation = true;
}
@@ -5741,6 +5746,7 @@
boolean split = mSplitShadeStateController.shouldUseSplitNotificationShade(getResources());
if (split != mShouldUseSplitNotificationShade) {
mShouldUseSplitNotificationShade = split;
+ mShouldSkipTopPaddingAnimationAfterFold = true;
mAmbientState.setUseSplitShade(split);
updateDismissBehavior();
updateUseRoundedRectClipping();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterImpl.kt
index e1fba2e..7aa7976 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterImpl.kt
@@ -372,26 +372,6 @@
)
}
- override fun executeRunnableDismissingKeyguard(
- runnable: Runnable?,
- cancelAction: Runnable?,
- dismissShade: Boolean,
- afterKeyguardGone: Boolean,
- deferred: Boolean,
- willAnimateOnKeyguard: Boolean,
- customMessage: String?,
- ) {
- activityStarterInternal.executeRunnableDismissingKeyguard(
- runnable = runnable,
- cancelAction = cancelAction,
- dismissShade = dismissShade,
- afterKeyguardGone = afterKeyguardGone,
- deferred = deferred,
- willAnimateOnKeyguard = willAnimateOnKeyguard,
- customMessage = customMessage,
- )
- }
-
override fun postQSRunnableDismissingKeyguard(runnable: Runnable?) {
postOnUiThread {
statusBarStateController.setLeaveOpenOnKeyguardHide(true)
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 645769c..57d49b2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -33,7 +33,6 @@
import static com.android.systemui.statusbar.StatusBarState.SHADE;
import android.annotation.Nullable;
-import android.app.ActivityManager;
import android.app.ActivityOptions;
import android.app.IWallpaperManager;
import android.app.KeyguardManager;
@@ -200,7 +199,7 @@
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.core.StatusBarInitializer;
import com.android.systemui.statusbar.data.model.StatusBarMode;
-import com.android.systemui.statusbar.data.repository.StatusBarModeRepository;
+import com.android.systemui.statusbar.data.repository.StatusBarModeRepositoryStore;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
import com.android.systemui.statusbar.notification.NotificationActivityStarter;
import com.android.systemui.statusbar.notification.NotificationLaunchAnimatorControllerProvider;
@@ -388,7 +387,7 @@
private final NotificationShadeWindowController mNotificationShadeWindowController;
private final StatusBarInitializer mStatusBarInitializer;
private final StatusBarWindowController mStatusBarWindowController;
- private final StatusBarModeRepository mStatusBarModeRepository;
+ private final StatusBarModeRepositoryStore mStatusBarModeRepository;
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@VisibleForTesting
DozeServiceHost mDozeServiceHost;
@@ -606,7 +605,7 @@
StatusBarInitializer statusBarInitializer,
StatusBarWindowController statusBarWindowController,
StatusBarWindowStateController statusBarWindowStateController,
- StatusBarModeRepository statusBarModeRepository,
+ StatusBarModeRepositoryStore statusBarModeRepository,
KeyguardUpdateMonitor keyguardUpdateMonitor,
StatusBarSignalPolicy statusBarSignalPolicy,
PulseExpansionHandler pulseExpansionHandler,
@@ -900,7 +899,7 @@
setUpPresenter();
if ((result.mTransientBarTypes & WindowInsets.Type.statusBars()) != 0) {
- mStatusBarModeRepository.showTransient();
+ mStatusBarModeRepository.getDefaultDisplay().showTransient();
}
mCommandQueueCallbacks.onSystemBarAttributesChanged(mDisplayId, result.mAppearance,
result.mAppearanceRegions, result.mNavbarColorManagedByIme, result.mBehavior,
@@ -1147,9 +1146,10 @@
mDemoModeController.addCallback(mDemoModeCallback);
mJavaAdapter.alwaysCollectFlow(
- mStatusBarModeRepository.isTransientShown(), this::onTransientShownChanged);
+ mStatusBarModeRepository.getDefaultDisplay().isTransientShown(),
+ this::onTransientShownChanged);
mJavaAdapter.alwaysCollectFlow(
- mStatusBarModeRepository.getStatusBarMode(),
+ mStatusBarModeRepository.getDefaultDisplay().getStatusBarMode(),
this::updateBarMode);
mCommandQueueCallbacks = mCommandQueueCallbacksLazy.get();
@@ -1209,7 +1209,7 @@
@Override
public void hide() {
- mStatusBarModeRepository.clearTransient();
+ mStatusBarModeRepository.getDefaultDisplay().clearTransient();
}
});
@@ -1657,7 +1657,7 @@
if (mDemoModeController.isInDemoMode()) return;
if (mStatusBarTransitions != null) {
checkBarMode(
- mStatusBarModeRepository.getStatusBarMode().getValue(),
+ mStatusBarModeRepository.getDefaultDisplay().getStatusBarMode().getValue(),
mStatusBarWindowState,
mStatusBarTransitions);
}
@@ -1668,7 +1668,8 @@
/** Temporarily hides Bubbles if the status bar is hidden. */
@Override
public void updateBubblesVisibility() {
- StatusBarMode mode = mStatusBarModeRepository.getStatusBarMode().getValue();
+ StatusBarMode mode =
+ mStatusBarModeRepository.getDefaultDisplay().getStatusBarMode().getValue();
mBubblesOptional.ifPresent(bubbles -> bubbles.onStatusBarVisibilityChanged(
mode != StatusBarMode.LIGHTS_OUT
&& mode != StatusBarMode.LIGHTS_OUT_TRANSPARENT
@@ -2927,45 +2928,6 @@
}
}
- /**
- * Dismiss the keyguard then execute an action.
- *
- * @param action The action to execute after dismissing the keyguard.
- * @param collapsePanel Whether we should collapse the panel after dismissing the keyguard.
- * @param willAnimateOnKeyguard Whether {@param action} will run an animation on the keyguard if
- * we are locked.
- */
- private void executeActionDismissingKeyguard(Runnable action, boolean afterKeyguardGone,
- boolean collapsePanel, boolean willAnimateOnKeyguard) {
- if (!mDeviceProvisionedController.isDeviceProvisioned()) return;
-
- OnDismissAction onDismissAction = new OnDismissAction() {
- @Override
- public boolean onDismiss() {
- new Thread(() -> {
- try {
- // The intent we are sending is for the application, which
- // won't have permission to immediately start an activity after
- // the user switches to home. We know it is safe to do at this
- // point, so make sure new activity switches are now allowed.
- ActivityManager.getService().resumeAppSwitches();
- } catch (RemoteException e) {
- }
- action.run();
- }).start();
-
- return collapsePanel ? mShadeController.collapseShade() : willAnimateOnKeyguard;
- }
-
- @Override
- public boolean willRunAnimationOnKeyguard() {
- return willAnimateOnKeyguard;
- }
- };
- mActivityStarter.dismissKeyguardThenExecute(onDismissAction, /* cancel= */ null,
- afterKeyguardGone);
- }
-
private void clearNotificationEffects() {
try {
mBarService.clearNotificationEffects();
@@ -2993,7 +2955,7 @@
// End Extra BaseStatusBarMethods.
boolean isTransientShown() {
- return mStatusBarModeRepository.isTransientShown().getValue();
+ return mStatusBarModeRepository.getDefaultDisplay().isTransientShown().getValue();
}
private void updateLightRevealScrimVisibility() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt
index b0183d3..674f169 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt
@@ -98,7 +98,7 @@
FACE_UNLOCK_BYPASS_NEVER -> false
else -> field
}
- return enabled && mKeyguardStateController.isFaceEnrolled &&
+ return enabled && mKeyguardStateController.isFaceEnrolledAndEnabled &&
isPostureAllowedForFaceAuth()
}
private set(value) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt
index 3329844..32b3ac2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt
@@ -22,7 +22,6 @@
import android.hardware.TriggerEvent
import android.hardware.TriggerEventListener
import com.android.keyguard.ActiveUnlockConfig
-import com.android.keyguard.FaceAuthApiRequestReason
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.keyguard.KeyguardUpdateMonitorCallback
import com.android.systemui.CoreStartable
@@ -77,9 +76,6 @@
isListening = false
updateListeningState()
keyguardFaceAuthInteractor.onDeviceLifted()
- keyguardUpdateMonitor.requestFaceAuth(
- FaceAuthApiRequestReason.PICK_UP_GESTURE_TRIGGERED
- )
keyguardUpdateMonitor.requestActiveUnlock(
ActiveUnlockConfig.ActiveUnlockRequestOrigin.WAKE,
"KeyguardLiftController")
@@ -117,7 +113,8 @@
val onKeyguard = keyguardUpdateMonitor.isKeyguardVisible &&
!statusBarStateController.isDozing
- val shouldListen = (onKeyguard || bouncerVisible) && keyguardUpdateMonitor.isFaceEnrolled
+ val isFaceEnabled = keyguardFaceAuthInteractor.isFaceAuthEnabledAndEnrolled()
+ val shouldListen = (onKeyguard || bouncerVisible) && isFaceEnabled
if (shouldListen != isListening) {
isListening = shouldListen
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightsOutNotifController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LegacyLightsOutNotifController.java
similarity index 94%
rename from packages/SystemUI/src/com/android/systemui/statusbar/phone/LightsOutNotifController.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/phone/LegacyLightsOutNotifController.java
index eba7fe0..7c871e1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightsOutNotifController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LegacyLightsOutNotifController.java
@@ -36,6 +36,7 @@
import com.android.internal.view.AppearanceRegion;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.notification.collection.NotifLiveDataStore;
+import com.android.systemui.statusbar.notification.shared.NotificationsLiveDataStoreRefactor;
import com.android.systemui.statusbar.phone.fragment.dagger.StatusBarFragmentScope;
import com.android.systemui.util.ViewController;
@@ -51,7 +52,7 @@
* whether there are notifications when the device is in {@link View#SYSTEM_UI_FLAG_LOW_PROFILE}.
*/
@StatusBarFragmentScope
-public class LightsOutNotifController extends ViewController<View> {
+public class LegacyLightsOutNotifController extends ViewController<View> {
private final CommandQueue mCommandQueue;
private final NotifLiveDataStore mNotifDataStore;
private final WindowManager mWindowManager;
@@ -63,7 +64,7 @@
private int mDisplayId;
@Inject
- LightsOutNotifController(
+ LegacyLightsOutNotifController(
@Named(LIGHTS_OUT_NOTIF_VIEW) View lightsOutNotifView,
WindowManager windowManager,
NotifLiveDataStore notifDataStore,
@@ -72,7 +73,12 @@
mWindowManager = windowManager;
mNotifDataStore = notifDataStore;
mCommandQueue = commandQueue;
+ }
+ @Override
+ protected void onInit() {
+ super.onInit();
+ NotificationsLiveDataStoreRefactor.assertInLegacyMode();
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java
index 4d3e2ad..eec617b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java
@@ -42,7 +42,7 @@
import com.android.systemui.plugins.DarkIconDispatcher;
import com.android.systemui.settings.DisplayTracker;
import com.android.systemui.statusbar.data.model.StatusBarAppearance;
-import com.android.systemui.statusbar.data.repository.StatusBarModeRepository;
+import com.android.systemui.statusbar.data.repository.StatusBarModeRepositoryStore;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.util.Compile;
import com.android.systemui.util.kotlin.JavaAdapter;
@@ -68,7 +68,7 @@
private final JavaAdapter mJavaAdapter;
private final SysuiDarkIconDispatcher mStatusBarIconController;
private final BatteryController mBatteryController;
- private final StatusBarModeRepository mStatusBarModeRepository;
+ private final StatusBarModeRepositoryStore mStatusBarModeRepository;
private BiometricUnlockController mBiometricUnlockController;
private LightBarTransitionsController mNavigationBarController;
@@ -126,7 +126,7 @@
DarkIconDispatcher darkIconDispatcher,
BatteryController batteryController,
NavigationModeController navModeController,
- StatusBarModeRepository statusBarModeRepository,
+ StatusBarModeRepositoryStore statusBarModeRepository,
DumpManager dumpManager,
DisplayTracker displayTracker) {
mJavaAdapter = javaAdapter;
@@ -146,7 +146,7 @@
@Override
public void start() {
mJavaAdapter.alwaysCollectFlow(
- mStatusBarModeRepository.getStatusBarAppearance(),
+ mStatusBarModeRepository.getDefaultDisplay().getStatusBarAppearance(),
this::onStatusBarAppearanceChanged);
}
@@ -476,7 +476,7 @@
private final DarkIconDispatcher mDarkIconDispatcher;
private final BatteryController mBatteryController;
private final NavigationModeController mNavModeController;
- private final StatusBarModeRepository mStatusBarModeRepository;
+ private final StatusBarModeRepositoryStore mStatusBarModeRepository;
private final DumpManager mDumpManager;
private final DisplayTracker mDisplayTracker;
@@ -486,7 +486,7 @@
DarkIconDispatcher darkIconDispatcher,
BatteryController batteryController,
NavigationModeController navModeController,
- StatusBarModeRepository statusBarModeRepository,
+ StatusBarModeRepositoryStore statusBarModeRepository,
DumpManager dumpManager,
DisplayTracker displayTracker) {
mJavaAdapter = javaAdapter;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 274b50f..daadedb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -1636,13 +1636,6 @@
}
/**
- * Request to authenticate using face.
- */
- public void requestFace(boolean request) {
- mKeyguardUpdateManager.requestFaceAuthOnOccludingApp(request);
- }
-
- /**
* Request to authenticate using the fingerprint sensor. If the fingerprint sensor is udfps,
* uses the color provided by udfpsColor for the fingerprint icon.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/domain/interactor/LightsOutInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/domain/interactor/LightsOutInteractor.kt
new file mode 100644
index 0000000..ed8b3e8
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/domain/interactor/LightsOutInteractor.kt
@@ -0,0 +1,45 @@
+/*
+ * 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.systemui.statusbar.phone.domain.interactor
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.statusbar.data.model.StatusBarMode
+import com.android.systemui.statusbar.data.repository.StatusBarModeRepositoryStore
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.map
+
+/**
+ * Apps can request a low profile mode [android.view.View.SYSTEM_UI_FLAG_LOW_PROFILE] where status
+ * bar and navigation icons dim. In this mode, a notification dot appears where the notification
+ * icons would appear if they would be shown outside of this mode.
+ *
+ * This interactor knows whether the device is in [android.view.View.SYSTEM_UI_FLAG_LOW_PROFILE].
+ */
+@SysUISingleton
+class LightsOutInteractor
+@Inject
+constructor(private val repository: StatusBarModeRepositoryStore) {
+
+ fun isLowProfile(displayId: Int): Flow<Boolean> =
+ repository.forDisplay(displayId).statusBarMode.map {
+ when (it) {
+ StatusBarMode.LIGHTS_OUT,
+ StatusBarMode.LIGHTS_OUT_TRANSPARENT -> true
+ else -> false
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
index 7adc08c..49880d4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
@@ -43,7 +43,6 @@
import com.android.systemui.demomode.DemoMode;
import com.android.systemui.demomode.DemoModeController;
import com.android.systemui.dump.DumpManager;
-import com.android.systemui.flags.FeatureFlagsClassic;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.res.R;
import com.android.systemui.shade.ShadeExpansionStateManager;
@@ -139,7 +138,6 @@
private final OngoingCallController mOngoingCallController;
private final SystemStatusAnimationScheduler mAnimationScheduler;
private final StatusBarLocationPublisher mLocationPublisher;
- private final FeatureFlagsClassic mFeatureFlags;
private final NotificationIconAreaController mNotificationIconAreaController;
private final ShadeExpansionStateManager mShadeExpansionStateManager;
private final StatusBarIconController mStatusBarIconController;
@@ -228,7 +226,6 @@
StatusBarLocationPublisher locationPublisher,
NotificationIconAreaController notificationIconAreaController,
ShadeExpansionStateManager shadeExpansionStateManager,
- FeatureFlagsClassic featureFlags,
StatusBarIconController statusBarIconController,
DarkIconManager.Factory darkIconManagerFactory,
CollapsedStatusBarViewModel collapsedStatusBarViewModel,
@@ -258,7 +255,6 @@
mLocationPublisher = locationPublisher;
mNotificationIconAreaController = notificationIconAreaController;
mShadeExpansionStateManager = shadeExpansionStateManager;
- mFeatureFlags = featureFlags;
mStatusBarIconController = statusBarIconController;
mCollapsedStatusBarViewModel = collapsedStatusBarViewModel;
mCollapsedStatusBarViewBinder = collapsedStatusBarViewBinder;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/StatusBarFragmentComponent.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/StatusBarFragmentComponent.java
index 0618abb..96faa35 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/StatusBarFragmentComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/StatusBarFragmentComponent.java
@@ -18,8 +18,9 @@
import com.android.systemui.battery.BatteryMeterViewController;
import com.android.systemui.dagger.qualifiers.RootView;
+import com.android.systemui.statusbar.notification.shared.NotificationsLiveDataStoreRefactor;
import com.android.systemui.statusbar.phone.HeadsUpAppearanceController;
-import com.android.systemui.statusbar.phone.LightsOutNotifController;
+import com.android.systemui.statusbar.phone.LegacyLightsOutNotifController;
import com.android.systemui.statusbar.phone.PhoneStatusBarTransitions;
import com.android.systemui.statusbar.phone.PhoneStatusBarView;
import com.android.systemui.statusbar.phone.PhoneStatusBarViewController;
@@ -78,7 +79,9 @@
getBatteryMeterViewController().init();
getHeadsUpAppearanceController().init();
getPhoneStatusBarViewController().init();
- getLightsOutNotifController().init();
+ if (!NotificationsLiveDataStoreRefactor.isEnabled()) {
+ getLegacyLightsOutNotifController().init();
+ }
getStatusBarDemoMode().init();
}
@@ -101,7 +104,7 @@
/** */
@StatusBarFragmentScope
- LightsOutNotifController getLightsOutNotifController();
+ LegacyLightsOutNotifController getLegacyLightsOutNotifController();
/** */
@StatusBarFragmentScope
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
index b0532ce..0bdd1a5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
@@ -36,7 +36,7 @@
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.dump.DumpManager
import com.android.systemui.plugins.ActivityStarter
-import com.android.systemui.statusbar.data.repository.StatusBarModeRepository
+import com.android.systemui.statusbar.data.repository.StatusBarModeRepositoryStore
import com.android.systemui.statusbar.gesture.SwipeStatusBarAwayGestureHandler
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection
@@ -68,7 +68,7 @@
private val dumpManager: DumpManager,
private val statusBarWindowController: StatusBarWindowController,
private val swipeStatusBarAwayGestureHandler: SwipeStatusBarAwayGestureHandler,
- private val statusBarModeRepository: StatusBarModeRepository,
+ private val statusBarModeRepository: StatusBarModeRepositoryStore,
) : CallbackController<OngoingCallListener>, Dumpable, CoreStartable {
private var isFullscreen: Boolean = false
/** Non-null if there's an active call notification. */
@@ -129,7 +129,7 @@
dumpManager.registerDumpable(this)
notifCollection.addCollectionListener(notifListener)
scope.launch {
- statusBarModeRepository.isInFullscreenMode.collect {
+ statusBarModeRepository.defaultDisplay.isInFullscreenMode.collect {
isFullscreen = it
updateChipClickListener()
updateGestureListening()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/data/repository/OngoingCallRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/data/repository/OngoingCallRepository.kt
index da9c45a..9c78ab4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/data/repository/OngoingCallRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/data/repository/OngoingCallRepository.kt
@@ -27,7 +27,7 @@
*
* This class is used to break a dependency cycle between
* [com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController] and
- * [com.android.systemui.statusbar.data.repository.StatusBarModeRepository]. Instead, those two
+ * [com.android.systemui.statusbar.data.repository.StatusBarModeRepositoryStore]. Instead, those two
* classes both refer to this repository.
*/
@SysUISingleton
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 b9b88f4..7d7f49b 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
@@ -16,11 +16,15 @@
package com.android.systemui.statusbar.pipeline.shared.ui.binder
+import android.animation.Animator
+import android.animation.AnimatorListenerAdapter
import android.view.View
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.lifecycle.repeatWhenAttached
+import com.android.systemui.res.R
+import com.android.systemui.statusbar.notification.shared.NotificationsLiveDataStoreRefactor
import com.android.systemui.statusbar.pipeline.shared.ui.viewmodel.CollapsedStatusBarViewModel
import javax.inject.Inject
import kotlinx.coroutines.launch
@@ -61,9 +65,49 @@
listener.onTransitionFromLockscreenToDreamStarted()
}
}
+
+ if (NotificationsLiveDataStoreRefactor.isEnabled) {
+ val displayId = view.display.displayId
+ val lightsOutView: View = view.requireViewById(R.id.notification_lights_out)
+ launch {
+ viewModel.areNotificationsLightsOut(displayId).collect { show ->
+ animateLightsOutView(lightsOutView, show)
+ }
+ }
+ }
}
}
}
+
+ private fun animateLightsOutView(view: View, visible: Boolean) {
+ view.animate().cancel()
+
+ val alpha = if (visible) 1f else 0f
+ val duration = if (visible) 750L else 250L
+ val visibility = if (visible) View.VISIBLE else View.GONE
+
+ if (visible) {
+ view.alpha = 0f
+ view.visibility = View.VISIBLE
+ }
+
+ view
+ .animate()
+ .alpha(alpha)
+ .setDuration(duration)
+ .setListener(
+ object : AnimatorListenerAdapter() {
+ override fun onAnimationEnd(animation: Animator) {
+ view.alpha = alpha
+ view.visibility = visibility
+ // Unset the listener, otherwise this may persist for
+ // another view property animation
+ view.animate().setListener(null)
+ }
+ }
+ )
+ .start()
+ }
}
/** Listener for various events that may affect the status bar's visibility. */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModel.kt
index 15ab143..52a6d8c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModel.kt
@@ -20,11 +20,17 @@
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.shared.model.TransitionState
+import com.android.systemui.statusbar.notification.domain.interactor.ActiveNotificationsInteractor
+import com.android.systemui.statusbar.notification.shared.NotificationsLiveDataStoreRefactor
+import com.android.systemui.statusbar.phone.domain.interactor.LightsOutInteractor
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.emptyFlow
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
@@ -48,12 +54,25 @@
/** Emits whenever a transition from lockscreen to dream has started. */
val transitionFromLockscreenToDreamStartedEvent: Flow<Unit>
+
+ /**
+ * Apps can request a low profile mode [android.view.View.SYSTEM_UI_FLAG_LOW_PROFILE] where
+ * status bar and navigation icons dim. In this mode, a notification dot appears where the
+ * notification icons would appear if they would be shown outside of this mode.
+ *
+ * This flow tells when to show or hide the notification dot in the status bar to indicate
+ * whether there are notifications when the device is in
+ * [android.view.View.SYSTEM_UI_FLAG_LOW_PROFILE].
+ */
+ fun areNotificationsLightsOut(displayId: Int): Flow<Boolean>
}
@SysUISingleton
class CollapsedStatusBarViewModelImpl
@Inject
constructor(
+ private val lightsOutInteractor: LightsOutInteractor,
+ private val notificationsInteractor: ActiveNotificationsInteractor,
keyguardTransitionInteractor: KeyguardTransitionInteractor,
@Application coroutineScope: CoroutineScope,
) : CollapsedStatusBarViewModel {
@@ -69,4 +88,17 @@
keyguardTransitionInteractor.lockscreenToDreamingTransition
.filter { it.transitionState == TransitionState.STARTED }
.map {}
+
+ override fun areNotificationsLightsOut(displayId: Int): Flow<Boolean> =
+ if (NotificationsLiveDataStoreRefactor.isUnexpectedlyInLegacyMode()) {
+ emptyFlow()
+ } else {
+ combine(
+ notificationsInteractor.areAnyNotificationsPresent,
+ lightsOutInteractor.isLowProfile(displayId),
+ ) { hasNotifications, isLowProfile ->
+ hasNotifications && isLowProfile
+ }
+ .distinctUntilChanged()
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DevicePostureController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DevicePostureController.java
index bbba19d..87df180 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DevicePostureController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DevicePostureController.java
@@ -73,7 +73,11 @@
/** Callback to be notified about device posture changes. */
interface Callback {
- /** Called when the posture changes. */
+ /**
+ * Called when the posture changes. If there are multiple active displays ("concurrent"),
+ * this will report the physical posture of the device (also known as the base device
+ * state).
+ */
void onPostureChanged(@DevicePostureInt int posture);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DevicePostureControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DevicePostureControllerImpl.java
index a32a5ab..8365e0f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DevicePostureControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DevicePostureControllerImpl.java
@@ -36,8 +36,11 @@
/** Implementation of {@link DevicePostureController} using the DeviceStateManager. */
@SysUISingleton
public class DevicePostureControllerImpl implements DevicePostureController {
+ /** From androidx.window.common.COMMON_STATE_USE_BASE_STATE */
+ private static final int COMMON_STATE_USE_BASE_STATE = 1000;
private final List<Callback> mListeners = new ArrayList<>();
private int mCurrentDevicePosture = DEVICE_POSTURE_UNKNOWN;
+ private int mCurrentBasePosture = DEVICE_POSTURE_UNKNOWN;
private final SparseIntArray mDeviceStateToPostureMap = new SparseIntArray();
@@ -70,12 +73,25 @@
mDeviceStateToPostureMap.put(deviceState, posture);
}
- deviceStateManager.registerCallback(executor, state -> {
- Assert.isMainThread();
- mCurrentDevicePosture =
- mDeviceStateToPostureMap.get(state, DEVICE_POSTURE_UNKNOWN);
+ deviceStateManager.registerCallback(executor, new DeviceStateManager.DeviceStateCallback() {
+ @Override
+ public void onStateChanged(int state) {
+ Assert.isMainThread();
+ mCurrentDevicePosture =
+ mDeviceStateToPostureMap.get(state, DEVICE_POSTURE_UNKNOWN);
- mListeners.forEach(l -> l.onPostureChanged(mCurrentDevicePosture));
+ mListeners.forEach(l -> l.onPostureChanged(getDevicePosture()));
+ }
+
+ @Override
+ public void onBaseStateChanged(int state) {
+ Assert.isMainThread();
+ mCurrentBasePosture = mDeviceStateToPostureMap.get(state, DEVICE_POSTURE_UNKNOWN);
+
+ if (useBaseState()) {
+ mListeners.forEach(l -> l.onPostureChanged(getDevicePosture()));
+ }
+ }
});
}
@@ -93,6 +109,14 @@
@Override
public int getDevicePosture() {
- return mCurrentDevicePosture;
+ if (useBaseState()) {
+ return mCurrentBasePosture;
+ } else {
+ return mCurrentDevicePosture;
+ }
+ }
+
+ private boolean useBaseState() {
+ return mCurrentDevicePosture == COMMON_STATE_USE_BASE_STATE;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateController.java
index 52133ee..ad2b070 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateController.java
@@ -130,7 +130,7 @@
/**
* If there are faces enrolled and user enabled face auth on keyguard.
*/
- default boolean isFaceEnrolled() {
+ default boolean isFaceEnrolledAndEnabled() {
return false;
}
@@ -265,7 +265,7 @@
/**
* Triggered when face auth becomes available or unavailable. Value should be queried with
- * {@link KeyguardStateController#isFaceEnrolled()}.
+ * {@link KeyguardStateController#isFaceEnrolledAndEnabled()}.
*/
default void onFaceEnrolledChanged() {}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
index 8cc7e7d2..3deb9e7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
@@ -85,7 +85,7 @@
private boolean mTrustManaged;
private boolean mTrusted;
private boolean mDebugUnlocked = false;
- private boolean mFaceEnrolled;
+ private boolean mFaceEnrolledAndEnabled;
private float mDismissAmount = 0f;
private boolean mDismissingFromTouch = false;
@@ -260,16 +260,16 @@
|| (Build.IS_DEBUGGABLE && DEBUG_AUTH_WITH_ADB && mDebugUnlocked);
boolean trustManaged = mKeyguardUpdateMonitor.getUserTrustIsManaged(user);
boolean trusted = mKeyguardUpdateMonitor.getUserHasTrust(user);
- boolean faceEnrolled = mKeyguardUpdateMonitor.isFaceEnrolled(user);
+ boolean faceEnabledAndEnrolled = mKeyguardUpdateMonitor.isFaceEnabledAndEnrolled();
boolean changed = secure != mSecure || canDismissLockScreen != mCanDismissLockScreen
|| trustManaged != mTrustManaged || mTrusted != trusted
- || mFaceEnrolled != faceEnrolled;
+ || mFaceEnrolledAndEnabled != faceEnabledAndEnrolled;
if (changed || updateAlways) {
mSecure = secure;
mCanDismissLockScreen = canDismissLockScreen;
mTrusted = trusted;
mTrustManaged = trustManaged;
- mFaceEnrolled = faceEnrolled;
+ mFaceEnrolledAndEnabled = faceEnabledAndEnrolled;
mLogger.logKeyguardStateUpdate(
mSecure, mCanDismissLockScreen, mTrusted, mTrustManaged);
notifyUnlockedChanged();
@@ -290,8 +290,8 @@
}
@Override
- public boolean isFaceEnrolled() {
- return mFaceEnrolled;
+ public boolean isFaceEnrolledAndEnabled() {
+ return mFaceEnrolledAndEnabled;
}
@Override
@@ -416,7 +416,7 @@
pw.println(" mTrustManaged: " + mTrustManaged);
pw.println(" mTrusted: " + mTrusted);
pw.println(" mDebugUnlocked: " + mDebugUnlocked);
- pw.println(" mFaceEnrolled: " + mFaceEnrolled);
+ pw.println(" mFaceEnrolled: " + mFaceEnrolledAndEnabled);
pw.println(" isKeyguardFadingAway: " + isKeyguardFadingAway());
pw.println(" isKeyguardGoingAway: " + isKeyguardGoingAway());
pw.println(" isLaunchTransitionFadingAway: " + isLaunchTransitionFadingAway());
diff --git a/packages/SystemUI/src/com/android/systemui/unfold/SysUIUnfoldModule.kt b/packages/SystemUI/src/com/android/systemui/unfold/SysUIUnfoldModule.kt
index 1482cfc..8ae093a 100644
--- a/packages/SystemUI/src/com/android/systemui/unfold/SysUIUnfoldModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/unfold/SysUIUnfoldModule.kt
@@ -20,11 +20,12 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.shade.NotificationPanelUnfoldAnimationController
import com.android.systemui.statusbar.phone.StatusBarMoveFromCenterAnimationController
-import com.android.systemui.unfold.util.UnfoldKeyguardVisibilityManager
import com.android.systemui.unfold.util.NaturalRotationUnfoldProgressProvider
import com.android.systemui.unfold.util.ScopedUnfoldTransitionProgressProvider
+import com.android.systemui.unfold.util.UnfoldKeyguardVisibilityManager
import com.android.systemui.util.kotlin.getOrNull
import dagger.BindsInstance
+import dagger.Lazy
import dagger.Module
import dagger.Provides
import dagger.Subcomponent
@@ -54,10 +55,12 @@
@Provides
@SysUISingleton
fun provideSysUIUnfoldComponent(
- provider: Optional<UnfoldTransitionProgressProvider>,
- rotationProvider: Optional<NaturalRotationUnfoldProgressProvider>,
- @Named(UNFOLD_STATUS_BAR) scopedProvider: Optional<ScopedUnfoldTransitionProgressProvider>,
- factory: SysUIUnfoldComponent.Factory
+ provider: Optional<UnfoldTransitionProgressProvider>,
+ rotationProvider: Optional<NaturalRotationUnfoldProgressProvider>,
+ @Named(UNFOLD_STATUS_BAR) scopedProvider:
+ Optional<ScopedUnfoldTransitionProgressProvider>,
+ unfoldLatencyTracker: Lazy<UnfoldLatencyTracker>,
+ factory: SysUIUnfoldComponent.Factory
): Optional<SysUIUnfoldComponent> {
val p1 = provider.getOrNull()
val p2 = rotationProvider.getOrNull()
@@ -65,7 +68,7 @@
return if (p1 == null || p2 == null || p3 == null) {
Optional.empty()
} else {
- Optional.of(factory.create(p1, p2, p3))
+ Optional.of(factory.create(p1, p2, p3, unfoldLatencyTracker.get()))
}
}
}
@@ -73,13 +76,13 @@
@SysUIUnfoldScope
@Subcomponent
interface SysUIUnfoldComponent {
-
@Subcomponent.Factory
interface Factory {
fun create(
- @BindsInstance p1: UnfoldTransitionProgressProvider,
- @BindsInstance p2: NaturalRotationUnfoldProgressProvider,
- @BindsInstance p3: ScopedUnfoldTransitionProgressProvider
+ @BindsInstance p1: UnfoldTransitionProgressProvider,
+ @BindsInstance p2: NaturalRotationUnfoldProgressProvider,
+ @BindsInstance p3: ScopedUnfoldTransitionProgressProvider,
+ @BindsInstance p4: UnfoldLatencyTracker,
): SysUIUnfoldComponent
}
@@ -98,4 +101,8 @@
fun getUnfoldLightRevealOverlayAnimation(): UnfoldLightRevealOverlayAnimation
fun getUnfoldKeyguardVisibilityManager(): UnfoldKeyguardVisibilityManager
+
+ fun getUnfoldLatencyTracker(): UnfoldLatencyTracker
+
+ fun getNaturalRotationUnfoldProgressProvider(): NaturalRotationUnfoldProgressProvider
}
diff --git a/packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepository.kt b/packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepository.kt
index 5fc435a..cf76c0d 100644
--- a/packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepository.kt
@@ -29,7 +29,6 @@
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
-import com.android.systemui.flags.FeatureFlags
import com.android.systemui.res.R
import com.android.systemui.settings.UserTracker
import com.android.systemui.user.data.model.SelectedUserModel
@@ -120,7 +119,6 @@
@Background private val backgroundDispatcher: CoroutineDispatcher,
private val globalSettings: GlobalSettings,
private val tracker: UserTracker,
- featureFlags: FeatureFlags,
) : UserRepository {
private val _userSwitcherSettings: StateFlow<UserSwitcherSettingsModel> =
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
index d65a69c..9ee3d22 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
@@ -64,13 +64,13 @@
import com.android.internal.annotations.GuardedBy;
import com.android.settingslib.volume.MediaSessions;
import com.android.systemui.Dumpable;
-import com.android.systemui.res.R;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.plugins.VolumeDialogController;
import com.android.systemui.qs.tiles.DndTile;
+import com.android.systemui.res.R;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.VibratorHelper;
import com.android.systemui.util.RingerModeLiveData;
@@ -99,6 +99,7 @@
@SysUISingleton
public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpable {
private static final String TAG = Util.logTag(VolumeDialogControllerImpl.class);
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private static final int TOUCH_FEEDBACK_TIMEOUT_MS = 1000;
private static final int DYNAMIC_STREAM_START_INDEX = 100;
@@ -1339,14 +1340,24 @@
private boolean showForSession(Token token) {
if (mVolumeAdjustmentForRemoteGroupSessions) {
+ if (DEBUG) {
+ Log.d(TAG, "Volume adjustment for remote group sessions allowed,"
+ + " showForSession: true");
+ }
return true;
}
MediaController ctr = new MediaController(mContext, token);
String packageName = ctr.getPackageName();
List<RoutingSessionInfo> sessions =
mRouter2Manager.getRoutingSessions(packageName);
-
+ if (DEBUG) {
+ Log.d(TAG, "Found " + sessions.size() + " routing sessions for package name "
+ + packageName);
+ }
for (RoutingSessionInfo session : sessions) {
+ if (DEBUG) {
+ Log.d(TAG, "Found routingSessionInfo: " + session);
+ }
if (!session.isSystemSession()
&& session.getVolumeHandling() != MediaRoute2Info.PLAYBACK_VOLUME_FIXED) {
return true;
diff --git a/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletActivity.java b/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletActivity.java
index 2132904..5558aa7 100644
--- a/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletActivity.java
@@ -214,14 +214,12 @@
Utils.getColorAttrDefaultColor(
this, com.android.internal.R.attr.colorAccentPrimary));
mKeyguardFaceAuthInteractor.onWalletLaunched();
- mKeyguardViewManager.requestFace(true);
}
@Override
protected void onPause() {
super.onPause();
mKeyguardViewManager.requestFp(false, -1);
- mKeyguardViewManager.requestFace(false);
}
@Override
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/ActiveUnlockConfigTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/ActiveUnlockConfigTest.kt
index e429446..3f76d30 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/ActiveUnlockConfigTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/ActiveUnlockConfigTest.kt
@@ -261,7 +261,7 @@
// GIVEN fingerprint and face are NOT enrolled
activeUnlockConfig.keyguardUpdateMonitor = keyguardUpdateMonitor
- `when`(keyguardUpdateMonitor.isFaceEnrolled).thenReturn(false)
+ `when`(keyguardUpdateMonitor.isFaceEnabledAndEnrolled).thenReturn(false)
`when`(keyguardUpdateMonitor.isUnlockWithFingerprintPossible(0)).thenReturn(false)
// WHEN unlock intent is allowed when NO biometrics are enrolled (0)
@@ -291,7 +291,7 @@
// GIVEN fingerprint and face are both enrolled
activeUnlockConfig.keyguardUpdateMonitor = keyguardUpdateMonitor
- `when`(keyguardUpdateMonitor.isFaceEnrolled).thenReturn(true)
+ `when`(keyguardUpdateMonitor.isFaceEnabledAndEnrolled).thenReturn(true)
`when`(keyguardUpdateMonitor.isUnlockWithFingerprintPossible(0)).thenReturn(true)
// WHEN unlock intent is allowed when ONLY fingerprint is enrolled or NO biometircs
@@ -314,7 +314,7 @@
)
// WHEN fingerprint ONLY enrolled
- `when`(keyguardUpdateMonitor.isFaceEnrolled).thenReturn(false)
+ `when`(keyguardUpdateMonitor.isFaceEnabledAndEnrolled).thenReturn(false)
`when`(keyguardUpdateMonitor.isUnlockWithFingerprintPossible(0)).thenReturn(true)
// THEN active unlock triggers allowed on unlock intent
@@ -325,7 +325,7 @@
)
// WHEN face ONLY enrolled
- `when`(keyguardUpdateMonitor.isFaceEnrolled).thenReturn(true)
+ `when`(keyguardUpdateMonitor.isFaceEnabledAndEnrolled).thenReturn(true)
`when`(keyguardUpdateMonitor.isUnlockWithFingerprintPossible(0)).thenReturn(false)
// THEN active unlock triggers allowed on unlock intent
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
index 2e9b7e8..b403d1d 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
@@ -125,10 +125,7 @@
repository = repository,
)
- withDeps.featureFlags.apply {
- set(Flags.REGION_SAMPLING, false)
- set(Flags.FACE_AUTH_REFACTOR, false)
- }
+ withDeps.featureFlags.apply { set(Flags.REGION_SAMPLING, false) }
underTest =
ClockEventController(
withDeps.keyguardInteractor,
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerBaseTest.java
index 7feab91..adf0ada 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerBaseTest.java
@@ -18,7 +18,6 @@
import static android.view.View.INVISIBLE;
-import static com.android.systemui.flags.Flags.FACE_AUTH_REFACTOR;
import static com.android.systemui.flags.Flags.LOCKSCREEN_WALLPAPER_DREAM_ENABLED;
import static com.android.systemui.flags.Flags.MIGRATE_CLOCKS_TO_BLUEPRINT;
@@ -179,7 +178,6 @@
when(mSmartspaceController.buildAndConnectView(any())).thenReturn(mFakeSmartspaceView);
mExecutor = new FakeExecutor(new FakeSystemClock());
mFakeFeatureFlags = new FakeFeatureFlags();
- mFakeFeatureFlags.set(FACE_AUTH_REFACTOR, false);
mFakeFeatureFlags.set(LOCKSCREEN_WALLPAPER_DREAM_ENABLED, false);
mFakeFeatureFlags.set(MIGRATE_CLOCKS_TO_BLUEPRINT, false);
mController = new KeyguardClockSwitchController(
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
index 225f125..543b291 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
@@ -47,6 +47,7 @@
import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor
import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.flags.Flags
+import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractorFactory
import com.android.systemui.log.SessionTracker
@@ -137,6 +138,7 @@
@Mock private lateinit var viewMediatorCallback: ViewMediatorCallback
@Mock private lateinit var audioManager: AudioManager
@Mock private lateinit var mSelectedUserInteractor: SelectedUserInteractor
+ @Mock private lateinit var faceAuthInteractor: KeyguardFaceAuthInteractor
@Mock private lateinit var faceAuthAccessibilityDelegate: FaceAuthAccessibilityDelegate
@Mock private lateinit var deviceProvisionedController: DeviceProvisionedController
@Mock private lateinit var postureController: DevicePostureController
@@ -257,7 +259,7 @@
telephonyManager,
viewMediatorCallback,
audioManager,
- mock(),
+ faceAuthInteractor,
mock(),
{ JavaAdapter(sceneTestUtils.testScope.backgroundScope) },
mSelectedUserInteractor,
@@ -576,49 +578,12 @@
}
@Test
- fun onSwipeUp_whenFaceDetectionIsNotRunning_initiatesFaceAuth() {
+ fun onSwipeUp_forwardsItToFaceAuthInteractor() {
val registeredSwipeListener = registeredSwipeListener
- whenever(keyguardUpdateMonitor.isFaceDetectionRunning).thenReturn(false)
setupGetSecurityView(SecurityMode.Password)
registeredSwipeListener.onSwipeUp()
- verify(keyguardUpdateMonitor).requestFaceAuth(FaceAuthApiRequestReason.SWIPE_UP_ON_BOUNCER)
- }
- @Test
- fun onSwipeUp_whenFaceDetectionIsRunning_doesNotInitiateFaceAuth() {
- val registeredSwipeListener = registeredSwipeListener
- whenever(keyguardUpdateMonitor.isFaceDetectionRunning).thenReturn(true)
- registeredSwipeListener.onSwipeUp()
- verify(keyguardUpdateMonitor, never())
- .requestFaceAuth(FaceAuthApiRequestReason.SWIPE_UP_ON_BOUNCER)
- }
-
- @Test
- fun onSwipeUp_whenFaceDetectionIsTriggered_hidesBouncerMessage() {
- val registeredSwipeListener = registeredSwipeListener
- whenever(
- keyguardUpdateMonitor.requestFaceAuth(FaceAuthApiRequestReason.SWIPE_UP_ON_BOUNCER)
- )
- .thenReturn(true)
- setupGetSecurityView(SecurityMode.Password)
- clearInvocations(viewFlipperController)
- registeredSwipeListener.onSwipeUp()
- viewControllerImmediately
- verify(keyguardPasswordViewControllerMock)
- .showMessage(/* message= */ null, /* colorState= */ null, /* animated= */ true)
- }
-
- @Test
- fun onSwipeUp_whenFaceDetectionIsNotTriggered_retainsBouncerMessage() {
- val registeredSwipeListener = registeredSwipeListener
- whenever(
- keyguardUpdateMonitor.requestFaceAuth(FaceAuthApiRequestReason.SWIPE_UP_ON_BOUNCER)
- )
- .thenReturn(false)
- setupGetSecurityView(SecurityMode.Password)
- registeredSwipeListener.onSwipeUp()
- verify(keyguardPasswordViewControllerMock, never())
- .showMessage(/* message= */ null, /* colorState= */ null, /* animated= */ true)
+ verify(faceAuthInteractor).onSwipeUpOnBouncer()
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index 2b41e080..1ab634c 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -23,24 +23,15 @@
import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ERROR_LOCKOUT_PERMANENT;
import static android.hardware.biometrics.SensorProperties.STRENGTH_CONVENIENCE;
import static android.hardware.biometrics.SensorProperties.STRENGTH_STRONG;
-import static android.hardware.face.FaceAuthenticateOptions.AUTHENTICATE_REASON_PRIMARY_BOUNCER_SHOWN;
-import static android.hardware.face.FaceAuthenticateOptions.AUTHENTICATE_REASON_STARTED_WAKING_UP;
import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_UDFPS_OPTICAL;
import static android.telephony.SubscriptionManager.DATA_ROAMING_DISABLE;
import static android.telephony.SubscriptionManager.NAME_SOURCE_CARRIER_ID;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST;
-import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN;
-import static com.android.keyguard.FaceAuthApiRequestReason.NOTIFICATION_PANEL_CLICKED;
-import static com.android.keyguard.KeyguardUpdateMonitor.BIOMETRIC_HELP_FACE_NOT_AVAILABLE;
import static com.android.keyguard.KeyguardUpdateMonitor.BIOMETRIC_STATE_CANCELLING_RESTARTING;
import static com.android.keyguard.KeyguardUpdateMonitor.DEFAULT_CANCEL_SIGNAL_TIMEOUT;
import static com.android.keyguard.KeyguardUpdateMonitor.HAL_POWER_PRESS_TIMEOUT;
-import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_ASLEEP;
-import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_AWAKE;
-import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_WAKING;
-import static com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_CLOSED;
import static com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_OPENED;
import static com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_UNKNOWN;
@@ -88,12 +79,7 @@
import android.hardware.biometrics.BiometricSourceType;
import android.hardware.biometrics.ComponentInfoInternal;
import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback;
-import android.hardware.display.DisplayManagerGlobal;
-import android.hardware.face.FaceAuthenticateOptions;
import android.hardware.face.FaceManager;
-import android.hardware.face.FaceSensorProperties;
-import android.hardware.face.FaceSensorPropertiesInternal;
-import android.hardware.face.IFaceAuthenticatorsRegisteredCallback;
import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.FingerprintSensorProperties;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
@@ -121,11 +107,6 @@
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.text.TextUtils;
-import android.view.Display;
-import android.view.DisplayAdjustments;
-import android.view.DisplayInfo;
-
-import androidx.annotation.NonNull;
import com.android.dx.mockito.inline.extended.ExtendedMockito;
import com.android.internal.jank.InteractionJankMonitor;
@@ -143,10 +124,13 @@
import com.android.systemui.biometrics.FingerprintInteractiveToAuthProvider;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dump.DumpManager;
-import com.android.systemui.keyguard.WakefulnessLifecycle;
+import com.android.systemui.keyguard.domain.interactor.FaceAuthenticationListener;
+import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor;
+import com.android.systemui.keyguard.shared.model.ErrorFaceAuthenticationStatus;
+import com.android.systemui.keyguard.shared.model.FaceDetectionStatus;
+import com.android.systemui.keyguard.shared.model.FailedFaceAuthenticationStatus;
import com.android.systemui.log.SessionTracker;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.settings.FakeDisplayTracker;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.shared.system.TaskStackChangeListeners;
@@ -199,7 +183,6 @@
TEST_CARRIER, TEST_CARRIER_2, NAME_SOURCE_CARRIER_ID, 0xFFFFFF, "",
DATA_ROAMING_DISABLE, null, null, null, null, false, null, "", true, TEST_GROUP_UUID,
TEST_CARRIER_ID, 0);
- private static final int FACE_SENSOR_ID = 0;
private static final int FINGERPRINT_SENSOR_ID = 1;
@Mock
@@ -217,8 +200,6 @@
@Mock
private FingerprintManager mFingerprintManager;
@Mock
- private FaceManager mFaceManager;
- @Mock
private BiometricManager mBiometricManager;
@Mock
private PackageManager mPackageManager;
@@ -277,19 +258,18 @@
@Mock
private IActivityTaskManager mActivityTaskManager;
@Mock
- private WakefulnessLifecycle mWakefulness;
- @Mock
private SelectedUserInteractor mSelectedUserInteractor;
+ @Mock
+ private KeyguardFaceAuthInteractor mFaceAuthInteractor;
+ @Captor
+ private ArgumentCaptor<FaceAuthenticationListener> mFaceAuthenticationListener;
- private List<FaceSensorPropertiesInternal> mFaceSensorProperties;
private List<FingerprintSensorPropertiesInternal> mFingerprintSensorProperties;
private final int mCurrentUserId = 100;
@Captor
private ArgumentCaptor<IBiometricEnabledOnKeyguardCallback>
mBiometricEnabledCallbackArgCaptor;
- @Captor
- private ArgumentCaptor<FaceManager.AuthenticationCallback> mAuthenticationCallbackCaptor;
// Direct executor
private final Executor mBackgroundExecutor = Runnable::run;
@@ -303,14 +283,11 @@
private FaceWakeUpTriggersConfig mFaceWakeUpTriggersConfig;
private IFingerprintAuthenticatorsRegisteredCallback
mFingerprintAuthenticatorsRegisteredCallback;
- private IFaceAuthenticatorsRegisteredCallback mFaceAuthenticatorsRegisteredCallback;
private final InstanceId mKeyguardInstanceId = InstanceId.fakeInstanceId(999);
- private FakeDisplayTracker mDisplayTracker;
@Before
public void setup() throws RemoteException {
MockitoAnnotations.initMocks(this);
- mDisplayTracker = new FakeDisplayTracker(mContext);
when(mSessionTracker.getSessionId(SESSION_KEYGUARD)).thenReturn(mKeyguardInstanceId);
when(mUserManager.isUserUnlocked(anyInt())).thenReturn(true);
@@ -358,12 +335,14 @@
mKeyguardUpdateMonitor = new TestableKeyguardUpdateMonitor(mContext);
setupBiometrics(mKeyguardUpdateMonitor);
+ mKeyguardUpdateMonitor.setFaceAuthInteractor(mFaceAuthInteractor);
+ verify(mFaceAuthInteractor).registerListener(mFaceAuthenticationListener.capture());
}
private void setupBiometrics(KeyguardUpdateMonitor keyguardUpdateMonitor)
throws RemoteException {
captureAuthenticatorsRegisteredCallbacks();
- setupFaceAuth(/* isClass3 */ false);
+ when(mFaceAuthInteractor.isFaceAuthStrong()).thenReturn(false);
setupFingerprintAuth(/* isClass3 */ true);
verify(mBiometricManager)
@@ -387,12 +366,6 @@
}
private void captureAuthenticatorsRegisteredCallbacks() throws RemoteException {
- ArgumentCaptor<IFaceAuthenticatorsRegisteredCallback> faceCaptor =
- ArgumentCaptor.forClass(IFaceAuthenticatorsRegisteredCallback.class);
- verify(mFaceManager).addAuthenticatorsRegisteredCallback(faceCaptor.capture());
- mFaceAuthenticatorsRegisteredCallback = faceCaptor.getValue();
- mFaceAuthenticatorsRegisteredCallback.onAllAuthenticatorsRegistered(mFaceSensorProperties);
-
ArgumentCaptor<IFingerprintAuthenticatorsRegisteredCallback> fingerprintCaptor =
ArgumentCaptor.forClass(IFingerprintAuthenticatorsRegisteredCallback.class);
verify(mFingerprintManager).addAuthenticatorsRegisteredCallback(
@@ -402,16 +375,6 @@
.onAllAuthenticatorsRegistered(mFingerprintSensorProperties);
}
- private void setupFaceAuth(boolean isClass3) throws RemoteException {
- when(mFaceManager.isHardwareDetected()).thenReturn(true);
- when(mAuthController.isFaceAuthEnrolled(anyInt())).thenReturn(true);
- mFaceSensorProperties =
- List.of(createFaceSensorProperties(/* supportsFaceDetection = */ false, isClass3));
- when(mFaceManager.getSensorPropertiesInternal()).thenReturn(mFaceSensorProperties);
- mFaceAuthenticatorsRegisteredCallback.onAllAuthenticatorsRegistered(mFaceSensorProperties);
- assertEquals(isClass3, mKeyguardUpdateMonitor.isFaceClass3());
- }
-
private void setupFingerprintAuth(boolean isClass3) throws RemoteException {
when(mAuthController.isFingerprintEnrolled(anyInt())).thenReturn(true);
when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
@@ -442,28 +405,6 @@
true /* resetLockoutRequiresHardwareAuthToken */);
}
- @NonNull
- private FaceSensorPropertiesInternal createFaceSensorProperties(
- boolean supportsFaceDetection, boolean isClass3) {
- final List<ComponentInfoInternal> componentInfo = new ArrayList<>();
- componentInfo.add(new ComponentInfoInternal("faceSensor" /* componentId */,
- "vendor/model/revision" /* hardwareVersion */, "1.01" /* firmwareVersion */,
- "00000001" /* serialNumber */, "" /* softwareVersion */));
- componentInfo.add(new ComponentInfoInternal("matchingAlgorithm" /* componentId */,
- "" /* hardwareVersion */, "" /* firmwareVersion */, "" /* serialNumber */,
- "vendor/version/revision" /* softwareVersion */));
-
- return new FaceSensorPropertiesInternal(
- FACE_SENSOR_ID /* id */,
- isClass3 ? STRENGTH_STRONG : STRENGTH_CONVENIENCE,
- 1 /* maxTemplatesAllowed */,
- componentInfo,
- FaceSensorProperties.TYPE_UNKNOWN,
- supportsFaceDetection /* supportsFaceDetection */,
- true /* supportsSelfIllumination */,
- false /* resetLockoutRequiresChallenge */);
- }
-
@After
public void tearDown() {
if (mMockitoSession != null) {
@@ -887,13 +828,9 @@
}
@Test
- public void whenDetectFace_biometricDetectCallback() throws RemoteException {
- ArgumentCaptor<FaceManager.FaceDetectionCallback> faceDetectCallbackCaptor =
- ArgumentCaptor.forClass(FaceManager.FaceDetectionCallback.class);
-
- givenDetectFace();
- verify(mFaceManager).detectFace(any(), faceDetectCallbackCaptor.capture(), any());
- faceDetectCallbackCaptor.getValue().onFaceDetected(0, 0, false);
+ public void whenDetectFace_biometricDetectCallback() {
+ mFaceAuthenticationListener.getValue().onDetectionStatusChanged(
+ new FaceDetectionStatus(0, 0, false, 0L));
// THEN verify keyguardUpdateMonitorCallback receives a detect callback
// and NO authenticate callbacks
@@ -926,40 +863,10 @@
}
@Test
- public void class3FingerprintLockOut_lockOutClass1Face() throws RemoteException {
- setupFaceAuth(/* isClass3 */ false);
- setupFingerprintAuth(/* isClass3 */ true);
-
- // GIVEN primary auth is not required by StrongAuthTracker
- primaryAuthNotRequiredByStrongAuthTracker();
-
- // WHEN fingerprint (class 3) is lock out
- fingerprintErrorTemporaryLockOut();
-
- // THEN unlocking with face is not allowed
- Assert.assertFalse(mKeyguardUpdateMonitor.isUnlockingWithBiometricAllowed(
- BiometricSourceType.FACE));
- }
-
- @Test
- public void class3FingerprintLockOut_lockOutClass3Face() throws RemoteException {
- setupFaceAuth(/* isClass3 */ true);
- setupFingerprintAuth(/* isClass3 */ true);
-
- // GIVEN primary auth is not required by StrongAuthTracker
- primaryAuthNotRequiredByStrongAuthTracker();
-
- // WHEN fingerprint (class 3) is lock out
- fingerprintErrorTemporaryLockOut();
-
- // THEN unlocking with face is not allowed
- Assert.assertFalse(mKeyguardUpdateMonitor.isUnlockingWithBiometricAllowed(
- BiometricSourceType.FACE));
- }
-
- @Test
public void class3FaceLockOut_lockOutClass3Fingerprint() throws RemoteException {
- setupFaceAuth(/* isClass3 */ true);
+ when(mFaceAuthInteractor.isFaceAuthStrong()).thenReturn(true);
+ when(mFaceAuthInteractor.isFaceAuthEnabledAndEnrolled()).thenReturn(true);
+
setupFingerprintAuth(/* isClass3 */ true);
// GIVEN primary auth is not required by StrongAuthTracker
@@ -975,7 +882,7 @@
@Test
public void class1FaceLockOut_doesNotLockOutClass3Fingerprint() throws RemoteException {
- setupFaceAuth(/* isClass3 */ false);
+ when(mFaceAuthInteractor.isFaceAuthStrong()).thenReturn(false);
setupFingerprintAuth(/* isClass3 */ true);
// GIVEN primary auth is not required by StrongAuthTracker
@@ -1056,162 +963,6 @@
}
@Test
- public void testTriesToAuthenticate_whenBouncer() {
- setKeyguardBouncerVisibility(true);
- verifyFaceAuthenticateCall();
- }
-
- @Test
- public void testNoStartAuthenticate_whenAboutToShowBouncer() {
- mKeyguardUpdateMonitor.sendPrimaryBouncerChanged(
- /* bouncerIsOrWillBeShowing */ true, /* bouncerFullyShown */ false);
-
- verifyFaceAuthenticateNeverCalled();
- }
-
- @Test
- public void testTriesToAuthenticate_whenKeyguard() {
- keyguardIsVisible();
- mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON);
- mTestableLooper.processAllMessages();
-
- verifyFaceAuthenticateCall();
- verify(mUiEventLogger).logWithInstanceIdAndPosition(
- eq(FaceAuthUiEvent.FACE_AUTH_UPDATED_STARTED_WAKING_UP),
- eq(0),
- eq(null),
- any(),
- eq(PowerManager.WAKE_REASON_POWER_BUTTON));
- }
-
- @Test
- public void skipsAuthentication_whenStatusBarShadeLocked() {
- mStatusBarStateListener.onStateChanged(StatusBarState.SHADE_LOCKED);
- mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON);
- mTestableLooper.processAllMessages();
-
- keyguardIsVisible();
- verifyFaceAuthenticateNeverCalled();
- }
-
- @Test
- public void skipsAuthentication_whenStrongAuthRequired_nonBypass() {
- lockscreenBypassIsNotAllowed();
- when(mStrongAuthTracker.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(false);
-
- mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON);
- mTestableLooper.processAllMessages();
- keyguardIsVisible();
-
- verifyFaceAuthenticateNeverCalled();
- }
-
- @Test
- public void nofaceDetect_whenStrongAuthRequiredAndBypassUdfpsSupportedAndFpRunning()
- throws RemoteException {
- // GIVEN bypass is enabled, face detection is supported
- lockscreenBypassIsAllowed();
- supportsFaceDetection();
- keyguardIsVisible();
-
- // GIVEN udfps is supported and strong auth required for weak biometrics (face) only
- givenUdfpsSupported();
- primaryAuthRequiredForWeakBiometricOnly(); // allows class3 fp to run but not class1 face
-
- // WHEN the device wakes up
- mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON);
- mTestableLooper.processAllMessages();
-
- // THEN face detect and authenticate are NOT triggered
- verifyFaceDetectNeverCalled();
- verifyFaceAuthenticateNeverCalled();
-
- // THEN biometric help message sent to callback
- verify(mTestCallback).onBiometricHelp(
- eq(BIOMETRIC_HELP_FACE_NOT_AVAILABLE), anyString(), eq(BiometricSourceType.FACE));
- }
-
- @Test
- public void faceDetect_whenStrongAuthRequiredAndBypass() throws RemoteException {
- givenDetectFace();
-
- // FACE detect is triggered, not authenticate
- verifyFaceDetectCall();
- verifyFaceAuthenticateNeverCalled();
-
- // WHEN bouncer becomes visible
- setKeyguardBouncerVisibility(true);
- clearInvocations(mFaceManager);
-
- // THEN face scanning is not run
- mKeyguardUpdateMonitor.requestFaceAuth(FaceAuthApiRequestReason.UDFPS_POINTER_DOWN);
- verifyFaceAuthenticateNeverCalled();
- verifyFaceDetectNeverCalled();
- }
-
- @Test
- public void noFaceDetect_whenStrongAuthRequiredAndBypass_faceDetectionUnsupported() {
- // GIVEN bypass is enabled, face detection is NOT supported and strong auth is required
- lockscreenBypassIsAllowed();
- primaryAuthRequiredEncrypted();
- keyguardIsVisible();
-
- // WHEN the device wakes up
- mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON);
- mTestableLooper.processAllMessages();
-
- // FACE detect and authenticate are NOT triggered
- verifyFaceDetectNeverCalled();
- verifyFaceAuthenticateNeverCalled();
- }
-
- @Test
- public void requestFaceAuth_whenFaceAuthWasStarted_returnsTrue() throws RemoteException {
- // This satisfies all the preconditions to run face auth.
- keyguardNotGoingAway();
- currentUserIsSystem();
- currentUserDoesNotHaveTrust();
- biometricsNotDisabledThroughDevicePolicyManager();
- biometricsEnabledForCurrentUser();
- userNotCurrentlySwitching();
- bouncerFullyVisibleAndNotGoingToSleep();
- mTestableLooper.processAllMessages();
-
- boolean didFaceAuthRun = mKeyguardUpdateMonitor.requestFaceAuth(
- NOTIFICATION_PANEL_CLICKED);
-
- assertThat(didFaceAuthRun).isTrue();
- }
-
- @Test
- public void requestFaceAuth_whenFaceAuthWasNotStarted_returnsFalse() throws RemoteException {
- // This ensures face auth won't run.
- biometricsDisabledForCurrentUser();
- mTestableLooper.processAllMessages();
-
- boolean didFaceAuthRun = mKeyguardUpdateMonitor.requestFaceAuth(
- NOTIFICATION_PANEL_CLICKED);
-
- assertThat(didFaceAuthRun).isFalse();
- }
-
- @Test
- public void testTriesToAuthenticate_whenAssistant() {
- mKeyguardUpdateMonitor.setKeyguardShowing(true, true);
- mKeyguardUpdateMonitor.setAssistantVisible(true);
-
- verifyFaceAuthenticateCall();
- }
-
- @Test
- public void doesNotTryToAuthenticateWhenKeyguardIsNotShowingButOccluded_whenAssistant() {
- mKeyguardUpdateMonitor.setKeyguardShowing(false, true);
- mKeyguardUpdateMonitor.setAssistantVisible(true);
-
- verifyFaceAuthenticateNeverCalled();
- }
-
- @Test
public void noFpListeningWhenKeyguardIsOccluded_unlessAlternateBouncerShowing() {
// GIVEN device is awake but occluded
mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON);
@@ -1257,62 +1008,6 @@
}
@Test
- public void testTriesToAuthenticate_whenTrustOnAgentKeyguard_ifBypass() {
- mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON);
- mTestableLooper.processAllMessages();
- lockscreenBypassIsAllowed();
- mKeyguardUpdateMonitor.onTrustChanged(true /* enabled */, true /* newlyUnlocked */,
- mSelectedUserInteractor.getSelectedUserId(), 0 /* flags */,
- new ArrayList<>());
- keyguardIsVisible();
- verifyFaceAuthenticateCall();
- }
-
- @Test
- public void faceUnlockDoesNotRunWhenDeviceIsGoingToSleepWithAssistantVisible() {
- mKeyguardUpdateMonitor.setKeyguardShowing(true, true);
- mKeyguardUpdateMonitor.setAssistantVisible(true);
-
- verifyFaceAuthenticateCall();
- mTestableLooper.processAllMessages();
- clearInvocations(mFaceManager);
-
- // Device going to sleep while assistant is visible
- mKeyguardUpdateMonitor.handleStartedGoingToSleep(0);
- mKeyguardUpdateMonitor.handleFinishedGoingToSleep(0);
- mTestableLooper.moveTimeForward(DEFAULT_CANCEL_SIGNAL_TIMEOUT);
- mTestableLooper.processAllMessages();
-
- mKeyguardUpdateMonitor.handleKeyguardReset();
-
- assertThat(mKeyguardUpdateMonitor.isFaceDetectionRunning()).isFalse();
- verifyFaceAuthenticateNeverCalled();
- }
-
- @Test
- public void testIgnoresAuth_whenTrustAgentOnKeyguard_withoutBypass() {
- mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON);
- mTestableLooper.processAllMessages();
- mKeyguardUpdateMonitor.onTrustChanged(true /* enabled */, true /* newlyUnlocked */,
- mSelectedUserInteractor.getSelectedUserId(), 0 /* flags */, new ArrayList<>());
- keyguardIsVisible();
- verifyFaceAuthenticateNeverCalled();
- }
-
- @Test
- public void testNoFaceAuth_whenLockDown() {
- when(mStrongAuthTracker.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(false);
- userDeviceLockDown();
-
- mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON);
- keyguardIsVisible();
- mTestableLooper.processAllMessages();
-
- verifyFaceAuthenticateNeverCalled();
- verifyFaceDetectNeverCalled();
- }
-
- @Test
public void testFingerprintPowerPressed_restartsFingerprintListeningStateWithDelay() {
mKeyguardUpdateMonitor.mFingerprintAuthenticationCallback
.onAuthenticationError(FingerprintManager.BIOMETRIC_ERROR_POWER_PRESSED, "");
@@ -1329,18 +1024,6 @@
}
@Test
- public void testOnFaceAuthenticated_skipsFaceWhenAuthenticated() {
- // test whether face will be skipped if authenticated, so the value of isClass3Biometric
- // doesn't matter here
- mKeyguardUpdateMonitor.onFaceAuthenticated(mSelectedUserInteractor.getSelectedUserId(),
- true /* isClass3Biometric */);
- setKeyguardBouncerVisibility(true);
- mTestableLooper.processAllMessages();
-
- verifyFaceAuthenticateNeverCalled();
- }
-
- @Test
public void testFaceAndFingerprintLockout_onlyFace() {
mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON);
mTestableLooper.processAllMessages();
@@ -1379,7 +1062,11 @@
@Test
public void testGetUserCanSkipBouncer_whenFace() {
int user = mSelectedUserInteractor.getSelectedUserId();
- mKeyguardUpdateMonitor.onFaceAuthenticated(user, true /* isClass3Biometric */);
+ when(mStrongAuthTracker.isUnlockingWithBiometricAllowed(true /* isClass3Biometric */))
+ .thenReturn(true);
+ when(mFaceAuthInteractor.isFaceAuthStrong()).thenReturn(true);
+ when(mFaceAuthInteractor.isAuthenticated()).thenReturn(true);
+
assertThat(mKeyguardUpdateMonitor.getUserCanSkipBouncer(user)).isTrue();
}
@@ -1388,7 +1075,9 @@
when(mStrongAuthTracker.isUnlockingWithBiometricAllowed(false /* isClass3Biometric */))
.thenReturn(false);
int user = mSelectedUserInteractor.getSelectedUserId();
- mKeyguardUpdateMonitor.onFaceAuthenticated(user, false /* isClass3Biometric */);
+ when(mFaceAuthInteractor.isFaceAuthStrong()).thenReturn(false);
+ when(mFaceAuthInteractor.isAuthenticated()).thenReturn(true);
+
assertThat(mKeyguardUpdateMonitor.getUserCanSkipBouncer(user)).isFalse();
}
@@ -1409,22 +1098,19 @@
}
@Test
- public void testBiometricsCleared_whenUserSwitches() throws Exception {
+ public void testBiometricsCleared_whenUserSwitches() {
final BiometricAuthenticated dummyAuthentication =
new BiometricAuthenticated(true /* authenticated */, true /* strong */);
- mKeyguardUpdateMonitor.mUserFaceAuthenticated.put(0 /* user */, dummyAuthentication);
mKeyguardUpdateMonitor.mUserFingerprintAuthenticated.put(0 /* user */, dummyAuthentication);
assertThat(mKeyguardUpdateMonitor.mUserFingerprintAuthenticated.size()).isEqualTo(1);
- assertThat(mKeyguardUpdateMonitor.mUserFaceAuthenticated.size()).isEqualTo(1);
mKeyguardUpdateMonitor.handleUserSwitching(10 /* user */, () -> {
});
assertThat(mKeyguardUpdateMonitor.mUserFingerprintAuthenticated.size()).isEqualTo(0);
- assertThat(mKeyguardUpdateMonitor.mUserFaceAuthenticated.size()).isEqualTo(0);
}
@Test
- public void testMultiUserJankMonitor_whenUserSwitches() throws Exception {
+ public void testMultiUserJankMonitor_whenUserSwitches() {
mKeyguardUpdateMonitor.handleUserSwitchComplete(10 /* user */);
verify(mInteractionJankMonitor).end(InteractionJankMonitor.CUJ_USER_SWITCH);
verify(mLatencyTracker).onActionEnd(LatencyTracker.ACTION_USER_SWITCH);
@@ -1432,22 +1118,17 @@
@Test
public void testMultiUserLockoutChanged_whenUserSwitches() {
- testMultiUserLockout_whenUserSwitches(BiometricConstants.BIOMETRIC_LOCKOUT_PERMANENT,
- BiometricConstants.BIOMETRIC_LOCKOUT_PERMANENT);
+ testMultiUserLockout_whenUserSwitches(BiometricConstants.BIOMETRIC_LOCKOUT_PERMANENT);
}
@Test
public void testMultiUserLockoutNotChanged_whenUserSwitches() {
- testMultiUserLockout_whenUserSwitches(BiometricConstants.BIOMETRIC_LOCKOUT_NONE,
- BiometricConstants.BIOMETRIC_LOCKOUT_NONE);
+ testMultiUserLockout_whenUserSwitches(BiometricConstants.BIOMETRIC_LOCKOUT_NONE);
}
private void testMultiUserLockout_whenUserSwitches(
- @BiometricConstants.LockoutMode int fingerprintLockoutMode,
- @BiometricConstants.LockoutMode int faceLockoutMode) {
+ @BiometricConstants.LockoutMode int fingerprintLockoutMode) {
final int newUser = 12;
- final boolean faceLockOut =
- faceLockoutMode != BiometricConstants.BIOMETRIC_LOCKOUT_NONE;
final boolean fpLockOut =
fingerprintLockoutMode != BiometricConstants.BIOMETRIC_LOCKOUT_NONE;
@@ -1455,16 +1136,11 @@
mTestableLooper.processAllMessages();
keyguardIsVisible();
- verifyFaceAuthenticateCall();
verifyFingerprintAuthenticateCall();
when(mFingerprintManager.getLockoutModeForUser(eq(FINGERPRINT_SENSOR_ID), eq(newUser)))
.thenReturn(fingerprintLockoutMode);
- when(mFaceManager.getLockoutModeForUser(eq(FACE_SENSOR_ID), eq(newUser)))
- .thenReturn(faceLockoutMode);
- final CancellationSignal faceCancel = spy(mKeyguardUpdateMonitor.mFaceCancelSignal);
final CancellationSignal fpCancel = spy(mKeyguardUpdateMonitor.mFingerprintCancelSignal);
- mKeyguardUpdateMonitor.mFaceCancelSignal = faceCancel;
mKeyguardUpdateMonitor.mFingerprintCancelSignal = fpCancel;
KeyguardUpdateMonitorCallback callback = mock(KeyguardUpdateMonitorCallback.class);
mKeyguardUpdateMonitor.registerCallback(callback);
@@ -1472,17 +1148,13 @@
mKeyguardUpdateMonitor.handleUserSwitchComplete(newUser);
mTestableLooper.processAllMessages();
- // THEN face and fingerprint listening are always cancelled immediately
- verify(faceCancel).cancel();
- verify(callback).onBiometricRunningStateChanged(
- eq(false), eq(BiometricSourceType.FACE));
+ // THEN fingerprint listening are always cancelled immediately
verify(fpCancel).cancel();
verify(callback).onBiometricRunningStateChanged(
eq(false), eq(BiometricSourceType.FINGERPRINT));
// THEN locked out states are updated
assertThat(mKeyguardUpdateMonitor.isFingerprintLockedOut()).isEqualTo(fpLockOut);
- assertThat(mKeyguardUpdateMonitor.isFaceLockedOut()).isEqualTo(faceLockOut);
// Fingerprint should be cancelled on lockout if going to lockout state, else
// restarted if it's not
@@ -1752,11 +1424,11 @@
public void testShouldNotListenForUdfps_whenFaceAuthenticated() {
// GIVEN a "we should listen for udfps" state
mStatusBarStateListener.onStateChanged(StatusBarState.KEYGUARD);
+ when(mFaceAuthInteractor.isFaceAuthEnabledAndEnrolled()).thenReturn(true);
when(mStrongAuthTracker.hasUserAuthenticatedSinceBoot()).thenReturn(true);
// WHEN face authenticated
- mKeyguardUpdateMonitor.onFaceAuthenticated(
- mSelectedUserInteractor.getSelectedUserId(), false);
+ when(mFaceAuthInteractor.isAuthenticated()).thenReturn(true);
// THEN we shouldn't listen for udfps
assertThat(mKeyguardUpdateMonitor.shouldListenForFingerprint(true)).isEqualTo(false);
@@ -1777,51 +1449,6 @@
}
@Test
- public void testShouldNotUpdateBiometricListeningStateOnStatusBarStateChange() {
- // GIVEN state for face auth should run aside from StatusBarState
- biometricsNotDisabledThroughDevicePolicyManager();
- mStatusBarStateListener.onStateChanged(StatusBarState.SHADE_LOCKED);
- setKeyguardBouncerVisibility(false /* isVisible */);
- mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON);
- lockscreenBypassIsAllowed();
- keyguardIsVisible();
-
- // WHEN status bar state reports a change to the keyguard that would normally indicate to
- // start running face auth
- mStatusBarStateListener.onStateChanged(StatusBarState.KEYGUARD);
- assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isEqualTo(true);
-
- // THEN face unlock is not running b/c status bar state changes don't cause biometric
- // listening state to update
- assertThat(mKeyguardUpdateMonitor.isFaceDetectionRunning()).isEqualTo(false);
-
- // WHEN biometric listening state is updated when showing state changes from false => true
- mKeyguardUpdateMonitor.setKeyguardShowing(false, false);
- mKeyguardUpdateMonitor.setKeyguardShowing(true, false);
-
- // THEN face unlock is running
- assertThat(mKeyguardUpdateMonitor.isFaceDetectionRunning()).isEqualTo(true);
- }
-
- @Test
- public void testRequestFaceAuthFromOccludingApp_whenInvoked_startsFaceAuth() {
- mKeyguardUpdateMonitor.requestFaceAuthOnOccludingApp(true);
-
- assertThat(mKeyguardUpdateMonitor.isFaceDetectionRunning()).isTrue();
- }
-
- @Test
- public void testRequestFaceAuthFromOccludingApp_whenInvoked_stopsFaceAuth() {
- mKeyguardUpdateMonitor.requestFaceAuthOnOccludingApp(true);
-
- assertThat(mKeyguardUpdateMonitor.isFaceDetectionRunning()).isTrue();
-
- mKeyguardUpdateMonitor.requestFaceAuthOnOccludingApp(false);
-
- assertThat(mKeyguardUpdateMonitor.isFaceDetectionRunning()).isFalse();
- }
-
- @Test
public void testRequireUnlockForNfc_Broadcast() {
KeyguardUpdateMonitorCallback callback = mock(KeyguardUpdateMonitorCallback.class);
mKeyguardUpdateMonitor.registerCallback(callback);
@@ -1833,13 +1460,6 @@
}
@Test
- public void testFaceDoesNotAuth_afterPinAttempt() {
- mTestableLooper.processAllMessages();
- mKeyguardUpdateMonitor.setCredentialAttempted();
- verifyFaceAuthenticateNeverCalled();
- }
-
- @Test
public void testShowTrustGrantedMessage_onTrustGranted() {
// WHEN trust is enabled (ie: via some trust agent) with a trustGranted string
mKeyguardUpdateMonitor.onTrustChanged(true /* enabled */, true /* newlyUnlocked */,
@@ -1855,366 +1475,17 @@
}
@Test
- public void testShouldListenForFace_whenFaceManagerNotAvailable_returnsFalse() {
- cleanupKeyguardUpdateMonitor();
- mFaceManager = null;
-
- mKeyguardUpdateMonitor = new TestableKeyguardUpdateMonitor(mContext);
-
- assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isFalse();
- }
-
- @Test
- public void testShouldListenForFace_whenFpIsLockedOut_returnsFalse() throws RemoteException {
- // Face auth should run when the following is true.
- keyguardNotGoingAway();
- occludingAppRequestsFaceAuth();
- currentUserIsSystem();
- primaryAuthNotRequiredByStrongAuthTracker();
- biometricsEnabledForCurrentUser();
- currentUserDoesNotHaveTrust();
- biometricsNotDisabledThroughDevicePolicyManager();
- userNotCurrentlySwitching();
- mTestableLooper.processAllMessages();
- assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isTrue();
-
- // Fingerprint is locked out.
- fingerprintErrorTemporaryLockOut();
-
- assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isFalse();
- }
-
- @Test
- public void testShouldListenForFace_whenFaceIsAlreadyAuthenticated_returnsFalse()
- throws RemoteException {
- // Face auth should run when the following is true.
- bouncerFullyVisibleAndNotGoingToSleep();
- keyguardNotGoingAway();
- currentUserIsSystem();
- primaryAuthNotRequiredByStrongAuthTracker();
- biometricsEnabledForCurrentUser();
- currentUserDoesNotHaveTrust();
- biometricsNotDisabledThroughDevicePolicyManager();
- userNotCurrentlySwitching();
-
- mTestableLooper.processAllMessages();
-
- assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isTrue();
-
- triggerSuccessfulFaceAuth();
- mTestableLooper.processAllMessages();
-
- assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isFalse();
- }
-
- @Test
- public void testShouldListenForFace_whenFpIsAlreadyAuthenticated_returnsFalse()
- throws RemoteException {
- // Face auth should run when the following is true.
- bouncerFullyVisibleAndNotGoingToSleep();
- keyguardNotGoingAway();
- currentUserIsSystem();
- primaryAuthNotRequiredByStrongAuthTracker();
- biometricsEnabledForCurrentUser();
- currentUserDoesNotHaveTrust();
- biometricsNotDisabledThroughDevicePolicyManager();
- userNotCurrentlySwitching();
-
- mTestableLooper.processAllMessages();
-
- assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isTrue();
-
- successfulFingerprintAuth();
- mTestableLooper.processAllMessages();
-
- assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isFalse();
- }
-
- @Test
- public void testShouldListenForFace_whenUserIsNotPrimary_returnsFalse() throws RemoteException {
- cleanupKeyguardUpdateMonitor();
- // This disables face auth
- when(mUserManager.isSystemUser()).thenReturn(false);
- mKeyguardUpdateMonitor =
- new TestableKeyguardUpdateMonitor(mContext);
-
- // Face auth should run when the following is true.
- keyguardNotGoingAway();
- bouncerFullyVisibleAndNotGoingToSleep();
- primaryAuthNotRequiredByStrongAuthTracker();
- biometricsEnabledForCurrentUser();
- currentUserDoesNotHaveTrust();
- biometricsNotDisabledThroughDevicePolicyManager();
- userNotCurrentlySwitching();
- mTestableLooper.processAllMessages();
-
-
- assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isFalse();
- }
-
- @Test
- public void testShouldListenForFace_whenStrongAuthDoesNotAllowScanning_returnsFalse()
- throws RemoteException {
- // Face auth should run when the following is true.
- keyguardNotGoingAway();
- bouncerFullyVisibleAndNotGoingToSleep();
- currentUserIsSystem();
- biometricsEnabledForCurrentUser();
- currentUserDoesNotHaveTrust();
- biometricsNotDisabledThroughDevicePolicyManager();
- userNotCurrentlySwitching();
-
- // This disables face auth
- when(mStrongAuthTracker.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(false);
- mTestableLooper.processAllMessages();
-
- assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isFalse();
- }
-
- @Test
- public void testShouldListenForFace_whenBiometricsDisabledForUser_returnsFalse()
- throws RemoteException {
- keyguardNotGoingAway();
- bouncerFullyVisibleAndNotGoingToSleep();
- currentUserIsSystem();
- currentUserDoesNotHaveTrust();
- biometricsNotDisabledThroughDevicePolicyManager();
- biometricsEnabledForCurrentUser();
- userNotCurrentlySwitching();
- mTestableLooper.processAllMessages();
-
- assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isTrue();
-
- // This disables face auth
- biometricsDisabledForCurrentUser();
- mTestableLooper.processAllMessages();
-
- assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isFalse();
- }
-
- @Test
- public void testShouldListenForFace_whenUserCurrentlySwitching_returnsFalse()
- throws RemoteException {
- // Face auth should run when the following is true.
- keyguardNotGoingAway();
- bouncerFullyVisibleAndNotGoingToSleep();
- currentUserIsSystem();
- currentUserDoesNotHaveTrust();
- biometricsNotDisabledThroughDevicePolicyManager();
- biometricsEnabledForCurrentUser();
- userNotCurrentlySwitching();
- mTestableLooper.processAllMessages();
-
- assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isTrue();
-
- userCurrentlySwitching();
- mTestableLooper.processAllMessages();
-
- assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isFalse();
- }
-
- @Test
- public void testShouldListenForFace_whenSecureCameraLaunched_returnsFalse()
- throws RemoteException {
- keyguardNotGoingAway();
- bouncerFullyVisibleAndNotGoingToSleep();
- currentUserIsSystem();
- currentUserDoesNotHaveTrust();
- biometricsNotDisabledThroughDevicePolicyManager();
- biometricsEnabledForCurrentUser();
- userNotCurrentlySwitching();
- mTestableLooper.processAllMessages();
-
- assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isTrue();
-
- secureCameraLaunched();
- mTestableLooper.processAllMessages();
-
- assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isFalse();
- }
-
- @Test
- public void shouldListenForFace_secureCameraLaunchedButAlternateBouncerIsLaunched_returnsTrue()
- throws RemoteException {
- // Face auth should run when the following is true.
- keyguardNotGoingAway();
- bouncerFullyVisibleAndNotGoingToSleep();
- currentUserIsSystem();
- currentUserDoesNotHaveTrust();
- biometricsNotDisabledThroughDevicePolicyManager();
- biometricsEnabledForCurrentUser();
- userNotCurrentlySwitching();
- mTestableLooper.processAllMessages();
-
- secureCameraLaunched();
-
- assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isFalse();
-
- alternateBouncerVisible();
- mTestableLooper.processAllMessages();
-
- assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isTrue();
- }
-
- @Test
- public void testShouldListenForFace_whenBouncerShowingAndDeviceIsAwake_returnsTrue()
- throws RemoteException {
- // Face auth should run when the following is true.
- keyguardNotGoingAway();
- currentUserIsSystem();
- currentUserDoesNotHaveTrust();
- biometricsNotDisabledThroughDevicePolicyManager();
- biometricsEnabledForCurrentUser();
- userNotCurrentlySwitching();
- mTestableLooper.processAllMessages();
-
- assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isFalse();
-
- bouncerFullyVisibleAndNotGoingToSleep();
- mTestableLooper.processAllMessages();
-
- assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isTrue();
- }
-
- @Test
- public void testShouldListenForFace_whenAuthInterruptIsActive_returnsTrue()
- throws RemoteException {
- // Face auth should run when the following is true.
- keyguardNotGoingAway();
- currentUserIsSystem();
- currentUserDoesNotHaveTrust();
- biometricsNotDisabledThroughDevicePolicyManager();
- biometricsEnabledForCurrentUser();
- userNotCurrentlySwitching();
- mTestableLooper.processAllMessages();
-
- assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isFalse();
-
- triggerAuthInterrupt();
- mTestableLooper.processAllMessages();
-
- assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isTrue();
- }
-
- @Test
- public void testShouldListenForFace_whenKeyguardIsAwake_returnsTrue() throws RemoteException {
- // Preconditions for face auth to run
- keyguardNotGoingAway();
- currentUserIsSystem();
- currentUserDoesNotHaveTrust();
- biometricsNotDisabledThroughDevicePolicyManager();
- biometricsEnabledForCurrentUser();
- userNotCurrentlySwitching();
-
- statusBarShadeIsLocked();
- mTestableLooper.processAllMessages();
-
- assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isFalse();
-
- deviceNotGoingToSleep();
- assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isFalse();
- deviceIsInteractive();
- assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isFalse();
- keyguardIsVisible();
- assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isFalse();
- statusBarShadeIsNotLocked();
- assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isTrue();
- }
-
- @Test
- public void testShouldListenForFace_whenUdfpsFingerDown_returnsTrue() throws RemoteException {
- // Preconditions for face auth to run
- keyguardNotGoingAway();
- currentUserIsSystem();
- currentUserDoesNotHaveTrust();
- biometricsNotDisabledThroughDevicePolicyManager();
- biometricsEnabledForCurrentUser();
- userNotCurrentlySwitching();
- when(mAuthController.isUdfpsFingerDown()).thenReturn(false);
- mTestableLooper.processAllMessages();
-
- assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isFalse();
-
- when(mAuthController.isUdfpsFingerDown()).thenReturn(true);
- assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isTrue();
- }
-
- @Test
- public void testShouldListenForFace_whenAlternateBouncerIsShowing_returnsTrue()
- throws RemoteException {
- // Preconditions for face auth to run
- keyguardNotGoingAway();
- currentUserIsSystem();
- currentUserDoesNotHaveTrust();
- biometricsNotDisabledThroughDevicePolicyManager();
- biometricsEnabledForCurrentUser();
- userNotCurrentlySwitching();
- mTestableLooper.processAllMessages();
- assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isFalse();
-
- mKeyguardUpdateMonitor.setAlternateBouncerShowing(true);
-
- assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isTrue();
- }
-
- @Test
- public void testShouldListenForFace_alternateBouncerShowingButDeviceGoingToSleep_returnsFalse()
- throws RemoteException {
- // Preconditions for face auth to run
- keyguardNotGoingAway();
- currentUserIsSystem();
- currentUserDoesNotHaveTrust();
- biometricsNotDisabledThroughDevicePolicyManager();
- biometricsEnabledForCurrentUser();
- userNotCurrentlySwitching();
- deviceNotGoingToSleep();
- alternateBouncerVisible();
- mTestableLooper.processAllMessages();
- assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isTrue();
-
- deviceGoingToSleep();
- mTestableLooper.processAllMessages();
-
- assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isFalse();
- }
-
- private void alternateBouncerVisible() {
- mKeyguardUpdateMonitor.setAlternateBouncerShowing(true);
- }
-
- @Test
- public void testShouldListenForFace_whenFaceIsLockedOut_returnsTrue()
- throws RemoteException {
- // Preconditions for face auth to run
- keyguardNotGoingAway();
- currentUserIsSystem();
- currentUserDoesNotHaveTrust();
- biometricsNotDisabledThroughDevicePolicyManager();
- biometricsEnabledForCurrentUser();
- userNotCurrentlySwitching();
- mKeyguardUpdateMonitor.setAlternateBouncerShowing(true);
- mTestableLooper.processAllMessages();
- assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isTrue();
-
- // Face is locked out.
- faceAuthLockOut();
- mTestableLooper.processAllMessages();
-
- // This is needed beccause we want to show face locked out error message whenever face auth
- // is supposed to run.
- assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isTrue();
- }
-
- @Test
public void testFingerprintCanAuth_whenCancellationNotReceivedAndAuthFailed() {
mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON);
mTestableLooper.processAllMessages();
keyguardIsVisible();
- verifyFaceAuthenticateCall();
verifyFingerprintAuthenticateCall();
- mKeyguardUpdateMonitor.onFaceAuthenticated(0, false);
+ when(mFaceAuthInteractor.isAuthenticated()).thenReturn(true);
+ when(mFaceAuthInteractor.isFaceAuthStrong()).thenReturn(false);
+ when(mStrongAuthTracker.isUnlockingWithBiometricAllowed(false /* isClass3Biometric */))
+ .thenReturn(false);
// Make sure keyguard is going away after face auth attempt, and that it calls
// updateBiometricStateListeningState.
mKeyguardUpdateMonitor.setKeyguardShowing(false, false);
@@ -2234,34 +1505,6 @@
}
@Test
- public void testDreamingStopped_faceDoesNotRun() {
- mKeyguardUpdateMonitor.dispatchDreamingStopped();
- mTestableLooper.processAllMessages();
-
- verifyFaceAuthenticateNeverCalled();
- }
-
- @Test
- public void testFaceWakeupTrigger_runFaceAuth_onlyOnConfiguredTriggers() {
- // keyguard is visible
- keyguardIsVisible();
-
- // WHEN device wakes up from an application
- mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_APPLICATION);
- mTestableLooper.processAllMessages();
-
- // THEN face auth isn't triggered
- verifyFaceAuthenticateNeverCalled();
-
- // WHEN device wakes up from the power button
- mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON);
- mTestableLooper.processAllMessages();
-
- // THEN face auth is triggered
- verifyFaceAuthenticateCall();
- }
-
- @Test
public void testOnTrustGrantedForCurrentUser_dismissKeyguardRequested_deviceInteractive() {
// GIVEN device is interactive
deviceIsInteractive();
@@ -2422,18 +1665,15 @@
}
@Test
- public void testStrongAuthChange_lockDown_stopsFpAndFaceListeningState() {
- // GIVEN device is listening for face and fingerprint
+ public void testStrongAuthChange_lockDown_stopsFpListeningState() {
+ // GIVEN device is listening for fingerprint
mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON);
mTestableLooper.processAllMessages();
keyguardIsVisible();
- verifyFaceAuthenticateCall();
verifyFingerprintAuthenticateCall();
- final CancellationSignal faceCancel = spy(mKeyguardUpdateMonitor.mFaceCancelSignal);
final CancellationSignal fpCancel = spy(mKeyguardUpdateMonitor.mFingerprintCancelSignal);
- mKeyguardUpdateMonitor.mFaceCancelSignal = faceCancel;
mKeyguardUpdateMonitor.mFingerprintCancelSignal = fpCancel;
KeyguardUpdateMonitorCallback callback = mock(KeyguardUpdateMonitorCallback.class);
mKeyguardUpdateMonitor.registerCallback(callback);
@@ -2445,88 +1685,13 @@
mSelectedUserInteractor.getSelectedUserId());
mTestableLooper.processAllMessages();
- // THEN face and fingerprint listening are cancelled
- verify(faceCancel).cancel();
- verify(callback).onBiometricRunningStateChanged(
- eq(false), eq(BiometricSourceType.FACE));
+ // THEN fingerprint listening are cancelled
verify(fpCancel).cancel();
verify(callback).onBiometricRunningStateChanged(
eq(false), eq(BiometricSourceType.FINGERPRINT));
}
@Test
- public void testNonStrongBiometricAllowedChanged_stopsFaceListeningState() {
- // GIVEN device is listening for face and fingerprint
- mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON);
- mTestableLooper.processAllMessages();
- keyguardIsVisible();
-
- verifyFaceAuthenticateCall();
-
- final CancellationSignal faceCancel = spy(mKeyguardUpdateMonitor.mFaceCancelSignal);
- mKeyguardUpdateMonitor.mFaceCancelSignal = faceCancel;
- KeyguardUpdateMonitorCallback callback = mock(KeyguardUpdateMonitorCallback.class);
- mKeyguardUpdateMonitor.registerCallback(callback);
-
- // WHEN non-strong biometric allowed changes
- when(mStrongAuthTracker.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(false);
- mKeyguardUpdateMonitor.notifyNonStrongBiometricAllowedChanged(
- mSelectedUserInteractor.getSelectedUserId());
- mTestableLooper.processAllMessages();
-
- // THEN face and fingerprint listening are cancelled
- verify(faceCancel).cancel();
- verify(callback).onBiometricRunningStateChanged(
- eq(false), eq(BiometricSourceType.FACE));
- }
-
- @Test
- public void testPostureChangeToUnsupported_stopsFaceListeningState() {
- // GIVEN device is listening for face
- mKeyguardUpdateMonitor.mConfigFaceAuthSupportedPosture = DEVICE_POSTURE_CLOSED;
- deviceInPostureStateClosed();
- mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON);
- mTestableLooper.processAllMessages();
- keyguardIsVisible();
-
- verifyFaceAuthenticateCall();
-
- final CancellationSignal faceCancel = spy(mKeyguardUpdateMonitor.mFaceCancelSignal);
- mKeyguardUpdateMonitor.mFaceCancelSignal = faceCancel;
- KeyguardUpdateMonitorCallback callback = mock(KeyguardUpdateMonitorCallback.class);
- mKeyguardUpdateMonitor.registerCallback(callback);
-
- // WHEN device is opened
- deviceInPostureStateOpened();
- mTestableLooper.processAllMessages();
-
- // THEN face listening is stopped.
- verify(faceCancel).cancel();
- verify(callback).onBiometricRunningStateChanged(
- eq(false), eq(BiometricSourceType.FACE));
- }
-
- @Test
- public void testShouldListenForFace_withLockedDown_returnsFalse()
- throws RemoteException {
- keyguardNotGoingAway();
- bouncerFullyVisibleAndNotGoingToSleep();
- currentUserIsSystem();
- currentUserDoesNotHaveTrust();
- biometricsNotDisabledThroughDevicePolicyManager();
- biometricsEnabledForCurrentUser();
- userNotCurrentlySwitching();
- supportsFaceDetection();
- mTestableLooper.processAllMessages();
-
- assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isTrue();
-
- userDeviceLockDown();
-
- assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isFalse();
- }
-
- @Test
public void assistantVisible_requestActiveUnlock() {
// GIVEN active unlock requests from the assistant are allowed
when(mActiveUnlockConfig.shouldAllowActiveUnlockFromOrigin(
@@ -2549,8 +1714,7 @@
}
@Test
- public void fingerprintFailure_requestActiveUnlock_dismissKeyguard()
- throws RemoteException {
+ public void fingerprintFailure_requestActiveUnlock_dismissKeyguard() {
// GIVEN shouldTriggerActiveUnlock
bouncerFullyVisible();
when(mLockPatternUtils.isSecure(mSelectedUserInteractor.getSelectedUserId())).thenReturn(
@@ -2571,8 +1735,7 @@
}
@Test
- public void faceNonBypassFailure_requestActiveUnlock_doesNotDismissKeyguard()
- throws RemoteException {
+ public void faceNonBypassFailure_requestActiveUnlock_doesNotDismissKeyguard() {
// GIVEN shouldTriggerActiveUnlock
when(mAuthController.isUdfpsFingerDown()).thenReturn(false);
keyguardIsVisible();
@@ -2588,7 +1751,8 @@
// WHEN face fails & bypass is not allowed
lockscreenBypassIsNotAllowed();
- mKeyguardUpdateMonitor.mFaceAuthenticationCallback.onAuthenticationFailed();
+ mFaceAuthenticationListener.getValue().onAuthenticationStatusChanged(
+ new FailedFaceAuthenticationStatus());
// THEN request unlock with NO keyguard dismissal
verify(mTrustManager).reportUserRequestedUnlock(
@@ -2597,10 +1761,10 @@
}
@Test
- public void faceBypassFailure_requestActiveUnlock_dismissKeyguard()
- throws RemoteException {
+ public void faceBypassFailure_requestActiveUnlock_dismissKeyguard() {
// GIVEN shouldTriggerActiveUnlock
when(mAuthController.isUdfpsFingerDown()).thenReturn(false);
+ when(mFaceAuthInteractor.isFaceAuthEnabledAndEnrolled()).thenReturn(true);
keyguardIsVisible();
keyguardNotGoingAway();
statusBarShadeIsNotLocked();
@@ -2614,7 +1778,8 @@
// WHEN face fails & bypass is not allowed
lockscreenBypassIsAllowed();
- mKeyguardUpdateMonitor.mFaceAuthenticationCallback.onAuthenticationFailed();
+ mFaceAuthenticationListener.getValue().onAuthenticationStatusChanged(
+ new FailedFaceAuthenticationStatus());
// THEN request unlock with a keyguard dismissal
verify(mTrustManager).reportUserRequestedUnlock(
@@ -2623,10 +1788,10 @@
}
@Test
- public void faceNonBypassFailure_requestActiveUnlock_dismissKeyguard()
- throws RemoteException {
+ public void faceNonBypassFailure_requestActiveUnlock_dismissKeyguard() {
// GIVEN shouldTriggerActiveUnlock
when(mAuthController.isUdfpsFingerDown()).thenReturn(false);
+ when(mFaceAuthInteractor.isFaceAuthEnabledAndEnrolled()).thenReturn(true);
lockscreenBypassIsNotAllowed();
when(mLockPatternUtils.isSecure(mSelectedUserInteractor.getSelectedUserId())).thenReturn(
true);
@@ -2638,7 +1803,8 @@
// WHEN face fails & on the bouncer
bouncerFullyVisible();
- mKeyguardUpdateMonitor.mFaceAuthenticationCallback.onAuthenticationFailed();
+ mFaceAuthenticationListener.getValue().onAuthenticationStatusChanged(
+ new FailedFaceAuthenticationStatus());
// THEN request unlock with a keyguard dismissal
verify(mTrustManager).reportUserRequestedUnlock(
@@ -2647,54 +1813,6 @@
}
@Test
- public void testShouldListenForFace_withAuthSupportPostureConfig_returnsTrue()
- throws RemoteException {
- mKeyguardUpdateMonitor.mConfigFaceAuthSupportedPosture = DEVICE_POSTURE_CLOSED;
- keyguardNotGoingAway();
- bouncerFullyVisibleAndNotGoingToSleep();
- currentUserIsSystem();
- currentUserDoesNotHaveTrust();
- biometricsNotDisabledThroughDevicePolicyManager();
- biometricsEnabledForCurrentUser();
- userNotCurrentlySwitching();
- supportsFaceDetection();
-
- deviceInPostureStateOpened();
- mTestableLooper.processAllMessages();
- // Should not listen for face when posture state in DEVICE_POSTURE_OPENED
- assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isFalse();
-
- deviceInPostureStateClosed();
- mTestableLooper.processAllMessages();
- // Should listen for face when posture state in DEVICE_POSTURE_CLOSED
- assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isTrue();
- }
-
- @Test
- public void testShouldListenForFace_withoutAuthSupportPostureConfig_returnsTrue()
- throws RemoteException {
- mKeyguardUpdateMonitor.mConfigFaceAuthSupportedPosture = DEVICE_POSTURE_UNKNOWN;
- keyguardNotGoingAway();
- bouncerFullyVisibleAndNotGoingToSleep();
- currentUserIsSystem();
- currentUserDoesNotHaveTrust();
- biometricsNotDisabledThroughDevicePolicyManager();
- biometricsEnabledForCurrentUser();
- userNotCurrentlySwitching();
- supportsFaceDetection();
-
- deviceInPostureStateClosed();
- mTestableLooper.processAllMessages();
- // Whether device in any posture state, always listen for face
- assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isTrue();
-
- deviceInPostureStateOpened();
- mTestableLooper.processAllMessages();
- // Whether device in any posture state, always listen for face
- assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isTrue();
- }
-
- @Test
public void testBatteryChangedIntent_refreshBatteryInfo() {
mKeyguardUpdateMonitor.mBroadcastReceiver.onReceive(mContext, getBatteryIntent());
@@ -2727,8 +1845,7 @@
}
@Test
- public void unfoldWakeup_requestActiveUnlock_forceDismissKeyguard()
- throws RemoteException {
+ public void unfoldWakeup_requestActiveUnlock_forceDismissKeyguard() {
// GIVEN shouldTriggerActiveUnlock
keyguardIsVisible();
when(mLockPatternUtils.isSecure(mSelectedUserInteractor.getSelectedUserId())).thenReturn(
@@ -2754,8 +1871,7 @@
}
@Test
- public void unfoldWakeup_requestActiveUnlock_noDismissKeyguard()
- throws RemoteException {
+ public void unfoldWakeup_requestActiveUnlock_noDismissKeyguard() {
// GIVEN shouldTriggerActiveUnlock on wake from UNFOLD_DEVICE
keyguardIsVisible();
when(mLockPatternUtils.isSecure(mSelectedUserInteractor.getSelectedUserId())).thenReturn(
@@ -2781,8 +1897,7 @@
}
@Test
- public void unfoldFromPostureChange_requestActiveUnlock_forceDismissKeyguard()
- throws RemoteException {
+ public void unfoldFromPostureChange_requestActiveUnlock_forceDismissKeyguard() {
// GIVEN shouldTriggerActiveUnlock
keyguardIsVisible();
when(mLockPatternUtils.isSecure(mSelectedUserInteractor.getSelectedUserId())).thenReturn(
@@ -2809,8 +1924,7 @@
@Test
- public void unfoldFromPostureChange_requestActiveUnlock_noDismissKeyguard()
- throws RemoteException {
+ public void unfoldFromPostureChange_requestActiveUnlock_noDismissKeyguard() {
// GIVEN shouldTriggerActiveUnlock on wake from UNFOLD_DEVICE
keyguardIsVisible();
when(mLockPatternUtils.isSecure(mSelectedUserInteractor.getSelectedUserId())).thenReturn(
@@ -2859,44 +1973,6 @@
}
@Test
- public void faceAuthenticateOptions_bouncerAuthenticateReason() {
- // GIVEN the bouncer is fully visible
- bouncerFullyVisible();
-
- // WHEN authenticate is called
- ArgumentCaptor<FaceAuthenticateOptions> captor =
- ArgumentCaptor.forClass(FaceAuthenticateOptions.class);
- verify(mFaceManager).authenticate(any(), any(), any(), any(), captor.capture());
-
- // THEN the authenticate reason is attributed to the bouncer
- assertThat(captor.getValue().getAuthenticateReason())
- .isEqualTo(AUTHENTICATE_REASON_PRIMARY_BOUNCER_SHOWN);
- }
-
- @Test
- public void faceAuthenticateOptions_wakingUpAuthenticateReason_powerButtonWakeReason() {
- // GIVEN keyguard is visible
- keyguardIsVisible();
-
- // WHEN device wakes up from the power button
- mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON);
- mTestableLooper.processAllMessages();
-
- // THEN face auth is triggered
- ArgumentCaptor<FaceAuthenticateOptions> captor =
- ArgumentCaptor.forClass(FaceAuthenticateOptions.class);
- verify(mFaceManager).authenticate(any(), any(), any(), any(), captor.capture());
-
- // THEN the authenticate reason is attributed to the waking
- assertThat(captor.getValue().getAuthenticateReason())
- .isEqualTo(AUTHENTICATE_REASON_STARTED_WAKING_UP);
-
- // THEN the wake reason is attributed to the power button
- assertThat(captor.getValue().getWakeReason())
- .isEqualTo(PowerManager.WAKE_REASON_POWER_BUTTON);
- }
-
- @Test
public void testFingerprintSensorProperties() throws RemoteException {
mFingerprintAuthenticatorsRegisteredCallback.onAllAuthenticatorsRegistered(
new ArrayList<>());
@@ -2913,26 +1989,6 @@
}
@Test
- public void testFaceSensorProperties() throws RemoteException {
- // GIVEN no face sensor properties
- when(mAuthController.isFaceAuthEnrolled(anyInt())).thenReturn(true);
- mFaceAuthenticatorsRegisteredCallback.onAllAuthenticatorsRegistered(new ArrayList<>());
-
- // THEN face is not possible
- assertThat(mKeyguardUpdateMonitor.isUnlockWithFacePossible(
- mSelectedUserInteractor.getSelectedUserId())).isFalse();
-
- // WHEN there are face sensor properties
- mFaceAuthenticatorsRegisteredCallback.onAllAuthenticatorsRegistered(mFaceSensorProperties);
-
- // THEN face is possible but face does NOT start listening immediately
- assertThat(mKeyguardUpdateMonitor.isUnlockWithFacePossible(
- mSelectedUserInteractor.getSelectedUserId())).isTrue();
- verifyFaceAuthenticateNeverCalled();
- verifyFaceDetectNeverCalled();
- }
-
- @Test
public void testFingerprintListeningStateWhenOccluded() {
when(mAuthController.isUdfpsSupported()).thenReturn(true);
@@ -3014,123 +2070,11 @@
authCallback.getValue().onEnrollmentsChanged(BiometricAuthenticator.TYPE_FACE);
mTestableLooper.processAllMessages();
verify(callback).onBiometricEnrollmentStateChanged(BiometricSourceType.FACE);
- }
- @Test
- public void onDisplayOn_nothingHappens() throws RemoteException {
- // GIVEN
- keyguardIsVisible();
- enableStopFaceAuthOnDisplayOff();
-
- // WHEN the default display state changes to ON
- triggerDefaultDisplayStateChangeToOn();
-
- // THEN face auth is NOT started since we rely on STARTED_WAKING_UP to start face auth,
- // NOT the display on event
- verifyFaceAuthenticateNeverCalled();
- verifyFaceDetectNeverCalled();
- }
-
- @Test
- public void onDisplayOff_stopFaceAuth() throws RemoteException {
- enableStopFaceAuthOnDisplayOff();
-
- // GIVEN device is listening for face
- mKeyguardUpdateMonitor.setKeyguardShowing(true, false);
- mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON);
+ clearInvocations(callback);
+ mFaceAuthenticationListener.getValue().onAuthEnrollmentStateChanged(false);
mTestableLooper.processAllMessages();
- verifyFaceAuthenticateCall();
-
- final CancellationSignal faceCancel = spy(mKeyguardUpdateMonitor.mFaceCancelSignal);
- mKeyguardUpdateMonitor.mFaceCancelSignal = faceCancel;
- KeyguardUpdateMonitorCallback callback = mock(KeyguardUpdateMonitorCallback.class);
- mKeyguardUpdateMonitor.registerCallback(callback);
-
- // WHEN the default display state changes to OFF
- triggerDefaultDisplayStateChangeToOff();
-
- // THEN face listening is stopped.
- verify(faceCancel).cancel();
- verify(callback).onBiometricRunningStateChanged(
- eq(false), eq(BiometricSourceType.FACE));
- }
-
- @Test
- public void onDisplayOff_whileAsleep_doesNotStopFaceAuth() throws RemoteException {
- enableStopFaceAuthOnDisplayOff();
- when(mWakefulness.getWakefulness()).thenReturn(WAKEFULNESS_ASLEEP);
-
- // GIVEN device is listening for face
- mKeyguardUpdateMonitor.setKeyguardShowing(true, false);
- mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON);
- mTestableLooper.processAllMessages();
- verifyFaceAuthenticateCall();
-
- final CancellationSignal faceCancel = spy(mKeyguardUpdateMonitor.mFaceCancelSignal);
- mKeyguardUpdateMonitor.mFaceCancelSignal = faceCancel;
- KeyguardUpdateMonitorCallback callback = mock(KeyguardUpdateMonitorCallback.class);
- mKeyguardUpdateMonitor.registerCallback(callback);
-
- // WHEN the default display state changes to OFF
- triggerDefaultDisplayStateChangeToOff();
-
- // THEN face listening is NOT stopped.
- verify(faceCancel, never()).cancel();
- verify(callback, never()).onBiometricRunningStateChanged(
- eq(false), eq(BiometricSourceType.FACE));
- }
-
- @Test
- public void onDisplayOff_whileWaking_doesNotStopFaceAuth() throws RemoteException {
- enableStopFaceAuthOnDisplayOff();
- when(mWakefulness.getWakefulness()).thenReturn(WAKEFULNESS_WAKING);
-
- // GIVEN device is listening for face
- mKeyguardUpdateMonitor.setKeyguardShowing(true, false);
- mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON);
- mTestableLooper.processAllMessages();
- verifyFaceAuthenticateCall();
-
- final CancellationSignal faceCancel = spy(mKeyguardUpdateMonitor.mFaceCancelSignal);
- mKeyguardUpdateMonitor.mFaceCancelSignal = faceCancel;
- KeyguardUpdateMonitorCallback callback = mock(KeyguardUpdateMonitorCallback.class);
- mKeyguardUpdateMonitor.registerCallback(callback);
-
- // WHEN the default display state changes to OFF
- triggerDefaultDisplayStateChangeToOff();
-
- // THEN face listening is NOT stopped.
- verify(faceCancel, never()).cancel();
- verify(callback, never()).onBiometricRunningStateChanged(
- eq(false), eq(BiometricSourceType.FACE));
- }
-
- private void triggerDefaultDisplayStateChangeToOn() {
- triggerDefaultDisplayStateChangeTo(true);
- }
-
- private void triggerDefaultDisplayStateChangeToOff() {
- triggerDefaultDisplayStateChangeTo(false);
- }
-
- /**
- * @param on true for Display.STATE_ON, else Display.STATE_OFF
- */
- private void triggerDefaultDisplayStateChangeTo(boolean on) {
- DisplayManagerGlobal displayManagerGlobal = mock(DisplayManagerGlobal.class);
- DisplayInfo displayInfoWithDisplayState = new DisplayInfo();
- displayInfoWithDisplayState.state = on ? Display.STATE_ON : Display.STATE_OFF;
- when(displayManagerGlobal.getDisplayInfo(mDisplayTracker.getDefaultDisplayId()))
- .thenReturn(displayInfoWithDisplayState);
- mDisplayTracker.setAllDisplays(new Display[]{
- new Display(
- displayManagerGlobal,
- mDisplayTracker.getDefaultDisplayId(),
- displayInfoWithDisplayState,
- DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS
- )
- });
- mDisplayTracker.triggerOnDisplayChanged(mDisplayTracker.getDefaultDisplayId());
+ verify(callback).onBiometricEnrollmentStateChanged(BiometricSourceType.FACE);
}
private void verifyFingerprintAuthenticateNeverCalled() {
@@ -3151,37 +2095,12 @@
verify(mFingerprintManager).detectFingerprint(any(), any(), any());
}
- private void verifyFaceAuthenticateNeverCalled() {
- verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), any());
- verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt());
- }
-
- private void verifyFaceAuthenticateCall() {
- verify(mFaceManager).authenticate(any(), any(), any(), any(), any());
- }
-
- private void verifyFaceDetectNeverCalled() {
- verify(mFaceManager, never()).detectFace(any(), any(), any());
- }
-
- private void verifyFaceDetectCall() {
- verify(mFaceManager).detectFace(any(), any(), any());
- }
-
private void userDeviceLockDown() {
when(mStrongAuthTracker.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(false);
when(mStrongAuthTracker.getStrongAuthForUser(mCurrentUserId))
.thenReturn(STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN);
}
- private void supportsFaceDetection() throws RemoteException {
- final boolean isClass3 = !mFaceSensorProperties.isEmpty()
- && mFaceSensorProperties.get(0).sensorStrength == STRENGTH_STRONG;
- mFaceSensorProperties =
- List.of(createFaceSensorProperties(/* supportsFaceDetection = */ true, isClass3));
- mFaceAuthenticatorsRegisteredCallback.onAllAuthenticatorsRegistered(mFaceSensorProperties);
- }
-
private void lockscreenBypassIsAllowed() {
mockCanBypassLockscreen(true);
}
@@ -3204,38 +2123,20 @@
}
private void faceAuthLockOut() {
- mKeyguardUpdateMonitor.mFaceAuthenticationCallback
- .onAuthenticationError(FaceManager.FACE_ERROR_LOCKOUT_PERMANENT, "");
+ when(mFaceAuthInteractor.isLockedOut()).thenReturn(true);
+ mFaceAuthenticationListener.getValue().onAuthenticationStatusChanged(
+ new ErrorFaceAuthenticationStatus(FaceManager.FACE_ERROR_LOCKOUT_PERMANENT, "",
+ 0L));
}
private void statusBarShadeIsNotLocked() {
mStatusBarStateListener.onStateChanged(StatusBarState.KEYGUARD);
}
- private void statusBarShadeIsLocked() {
- mStatusBarStateListener.onStateChanged(StatusBarState.SHADE_LOCKED);
- }
-
private void keyguardIsVisible() {
mKeyguardUpdateMonitor.setKeyguardShowing(true, false);
}
- private void triggerAuthInterrupt() {
- mKeyguardUpdateMonitor.onAuthInterruptDetected(true);
- }
-
- private void occludingAppRequestsFaceAuth() {
- mKeyguardUpdateMonitor.requestFaceAuthOnOccludingApp(true);
- }
-
- private void secureCameraLaunched() {
- mKeyguardUpdateMonitor.onCameraLaunched();
- }
-
- private void userCurrentlySwitching() {
- mKeyguardUpdateMonitor.setSwitchingUser(true);
- }
-
private void fingerprintErrorTemporaryLockOut() {
mKeyguardUpdateMonitor.mFingerprintAuthenticationCallback
.onAuthenticationError(FINGERPRINT_ERROR_LOCKOUT, "Fingerprint locked out");
@@ -3245,100 +2146,25 @@
mKeyguardUpdateMonitor.mPostureCallback.onPostureChanged(DEVICE_POSTURE_OPENED);
}
- private void deviceInPostureStateClosed() {
- mKeyguardUpdateMonitor.mPostureCallback.onPostureChanged(DEVICE_POSTURE_CLOSED);
- }
-
- private void successfulFingerprintAuth() {
- mKeyguardUpdateMonitor.mFingerprintAuthenticationCallback
- .onAuthenticationSucceeded(
- new FingerprintManager.AuthenticationResult(null,
- null,
- mCurrentUserId,
- true));
- }
-
- private void triggerSuccessfulFaceAuth() {
- mKeyguardUpdateMonitor.requestFaceAuth(FaceAuthApiRequestReason.UDFPS_POINTER_DOWN);
- verify(mFaceManager).authenticate(any(),
- any(),
- mAuthenticationCallbackCaptor.capture(),
- any(),
- any());
- mAuthenticationCallbackCaptor.getValue()
- .onAuthenticationSucceeded(
- new FaceManager.AuthenticationResult(null, null, mCurrentUserId, false));
- }
-
private void currentUserIsSystem() {
when(mUserManager.isSystemUser()).thenReturn(true);
}
- private void biometricsNotDisabledThroughDevicePolicyManager() {
- when(mDevicePolicyManager.getKeyguardDisabledFeatures(null,
- mSelectedUserInteractor.getSelectedUserId())).thenReturn(0);
- }
-
private void biometricsEnabledForCurrentUser() throws RemoteException {
mBiometricEnabledOnKeyguardCallback.onChanged(true,
mSelectedUserInteractor.getSelectedUserId());
}
- private void biometricsDisabledForCurrentUser() throws RemoteException {
- mBiometricEnabledOnKeyguardCallback.onChanged(
- false,
- mSelectedUserInteractor.getSelectedUserId()
- );
- }
-
- private void primaryAuthRequiredEncrypted() {
- when(mStrongAuthTracker.getStrongAuthForUser(mSelectedUserInteractor.getSelectedUserId()))
- .thenReturn(STRONG_AUTH_REQUIRED_AFTER_BOOT);
- when(mStrongAuthTracker.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(false);
- }
-
- private void primaryAuthRequiredForWeakBiometricOnly() {
- when(mStrongAuthTracker.isUnlockingWithBiometricAllowed(eq(true))).thenReturn(true);
- when(mStrongAuthTracker.isUnlockingWithBiometricAllowed(eq(false))).thenReturn(false);
- }
-
private void primaryAuthNotRequiredByStrongAuthTracker() {
when(mStrongAuthTracker.getStrongAuthForUser(mSelectedUserInteractor.getSelectedUserId()))
.thenReturn(0);
when(mStrongAuthTracker.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(true);
}
- private void currentUserDoesNotHaveTrust() {
- mKeyguardUpdateMonitor.onTrustChanged(
- false,
- false,
- mSelectedUserInteractor.getSelectedUserId(),
- -1,
- new ArrayList<>()
- );
- }
-
- private void userNotCurrentlySwitching() {
- mKeyguardUpdateMonitor.setSwitchingUser(false);
- }
-
private void keyguardNotGoingAway() {
mKeyguardUpdateMonitor.setKeyguardGoingAway(false);
}
- private void bouncerFullyVisibleAndNotGoingToSleep() {
- bouncerFullyVisible();
- deviceNotGoingToSleep();
- }
-
- private void deviceNotGoingToSleep() {
- mKeyguardUpdateMonitor.dispatchFinishedGoingToSleep(/* value doesn't matter */1);
- }
-
- private void deviceGoingToSleep() {
- mKeyguardUpdateMonitor.dispatchStartedGoingToSleep(/* value doesn't matter */1);
- }
-
private void deviceIsInteractive() {
mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON);
}
@@ -3347,20 +2173,11 @@
setKeyguardBouncerVisibility(true);
}
- private void bouncerNotVisible() {
- setKeyguardBouncerVisibility(false);
- }
-
private void setKeyguardBouncerVisibility(boolean isVisible) {
mKeyguardUpdateMonitor.sendPrimaryBouncerChanged(isVisible, isVisible);
mTestableLooper.processAllMessages();
}
- private void givenUdfpsSupported() {
- when(mAuthController.isUdfpsSupported()).thenReturn(true);
- Assert.assertTrue(mKeyguardUpdateMonitor.isUdfpsSupported());
- }
-
private void setBroadcastReceiverPendingResult(BroadcastReceiver receiver) {
BroadcastReceiver.PendingResult pendingResult =
new BroadcastReceiver.PendingResult(Activity.RESULT_OK,
@@ -3386,31 +2203,6 @@
mTestableLooper.processAllMessages();
}
- private void givenDetectFace() throws RemoteException {
- // GIVEN bypass is enabled, face detection is supported and primary auth is required
- lockscreenBypassIsAllowed();
- supportsFaceDetection();
- primaryAuthRequiredEncrypted();
- keyguardIsVisible();
- // fingerprint is NOT running, UDFPS is NOT supported
-
- // WHEN the device wakes up
- mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON);
- mTestableLooper.processAllMessages();
- }
-
- private void enableStopFaceAuthOnDisplayOff() throws RemoteException {
- cleanupKeyguardUpdateMonitor();
- clearInvocations(mFaceManager);
- clearInvocations(mFingerprintManager);
- clearInvocations(mBiometricManager);
- clearInvocations(mStatusBarStateController);
- mKeyguardUpdateMonitor = new TestableKeyguardUpdateMonitor(mContext);
- setupBiometrics(mKeyguardUpdateMonitor);
- when(mWakefulness.getWakefulness()).thenReturn(WAKEFULNESS_AWAKE);
- assertThat(mDisplayTracker.getDisplayCallbacks().size()).isEqualTo(1);
- }
-
private Intent putPhoneInfo(Intent intent, Bundle data, Boolean simInited) {
int subscription = simInited
? 1/* mock subid=1 */ : SubscriptionManager.PLACEHOLDER_SUBSCRIPTION_ID_BASE;
@@ -3486,11 +2278,10 @@
mKeyguardUpdateMonitorLogger, mUiEventLogger, () -> mSessionTracker,
mTrustManager, mSubscriptionManager, mUserManager,
mDreamManager, mDevicePolicyManager, mSensorPrivacyManager, mTelephonyManager,
- mPackageManager, mFaceManager, mFingerprintManager, mBiometricManager,
+ mPackageManager, mFingerprintManager, mBiometricManager,
mFaceWakeUpTriggersConfig, mDevicePostureController,
Optional.of(mInteractiveToAuthProvider),
- mTaskStackChangeListeners, mActivityTaskManager, mDisplayTracker,
- mWakefulness, mSelectedUserInteractor);
+ mTaskStackChangeListeners, mSelectedUserInteractor, mActivityTaskManager);
setStrongAuthTracker(KeyguardUpdateMonitorTest.this.mStrongAuthTracker);
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java
index d2f45ae..3d7d701 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java
@@ -18,7 +18,6 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
import static com.android.systemui.flags.Flags.DOZING_MIGRATION_1;
-import static com.android.systemui.flags.Flags.FACE_AUTH_REFACTOR;
import static com.android.systemui.flags.Flags.LOCKSCREEN_ENABLE_LANDSCAPE;
import static com.android.systemui.flags.Flags.LOCKSCREEN_WALLPAPER_DREAM_ENABLED;
@@ -151,7 +150,6 @@
mSetFlagsRule.disableFlags(Flags.FLAG_KEYGUARD_BOTTOM_AREA_REFACTOR);
mFeatureFlags = new FakeFeatureFlags();
- mFeatureFlags.set(FACE_AUTH_REFACTOR, false);
mFeatureFlags.set(LOCKSCREEN_WALLPAPER_DREAM_ENABLED, false);
mFeatureFlags.set(LOCKSCREEN_ENABLE_LANDSCAPE, false);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/FaceScanningProviderFactoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/FaceScanningProviderFactoryTest.kt
index ea7cc3d..6c91c98 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/FaceScanningProviderFactoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/FaceScanningProviderFactoryTest.kt
@@ -100,7 +100,7 @@
@Test
fun shouldNotShowFaceScanningAnimationIfFaceIsNotEnrolled() {
- whenever(keyguardUpdateMonitor.isFaceEnrolled).thenReturn(false)
+ whenever(keyguardUpdateMonitor.isFaceEnabledAndEnrolled).thenReturn(false)
whenever(authController.isShowing).thenReturn(true)
assertThat(underTest.shouldShowFaceScanningAnim()).isFalse()
@@ -108,7 +108,7 @@
@Test
fun shouldShowFaceScanningAnimationIfBiometricPromptIsShowing() {
- whenever(keyguardUpdateMonitor.isFaceEnrolled).thenReturn(true)
+ whenever(keyguardUpdateMonitor.isFaceEnabledAndEnrolled).thenReturn(true)
whenever(authController.isShowing).thenReturn(true)
assertThat(underTest.shouldShowFaceScanningAnim()).isTrue()
@@ -116,7 +116,7 @@
@Test
fun shouldShowFaceScanningAnimationIfKeyguardFaceDetectionIsShowing() {
- whenever(keyguardUpdateMonitor.isFaceEnrolled).thenReturn(true)
+ whenever(keyguardUpdateMonitor.isFaceEnabledAndEnrolled).thenReturn(true)
whenever(keyguardUpdateMonitor.isFaceDetectionRunning).thenReturn(true)
assertThat(underTest.shouldShowFaceScanningAnim()).isTrue()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthDialogPanelInteractionDetectorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthDialogPanelInteractionDetectorTest.kt
index 00ea78f..993dbac 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthDialogPanelInteractionDetectorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthDialogPanelInteractionDetectorTest.kt
@@ -65,10 +65,7 @@
.create(
test = this,
featureFlags =
- FakeFeatureFlagsClassicModule {
- set(Flags.FACE_AUTH_REFACTOR, false)
- set(Flags.FULL_SCREEN_USER_SWITCHER, true)
- },
+ FakeFeatureFlagsClassicModule { set(Flags.FULL_SCREEN_USER_SWITCHER, true) },
)
private val detector: AuthDialogPanelInteractionDetector = testComponent.underTest
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/FaceAuthAccessibilityDelegateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/FaceAuthAccessibilityDelegateTest.kt
index ec17794..86b9b84 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/FaceAuthAccessibilityDelegateTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/FaceAuthAccessibilityDelegateTest.kt
@@ -21,13 +21,10 @@
import android.view.accessibility.AccessibilityNodeInfo
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
-import com.android.keyguard.FaceAuthApiRequestReason
-import com.android.keyguard.KeyguardUpdateMonitor
import com.android.systemui.SysuiTestCase
import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.argumentCaptor
-import com.android.systemui.util.mockito.eq
import com.android.systemui.util.mockito.whenever
import org.junit.Assert.assertEquals
import org.junit.Before
@@ -44,7 +41,6 @@
@TestableLooper.RunWithLooper
class FaceAuthAccessibilityDelegateTest : SysuiTestCase() {
- @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
@Mock private lateinit var hostView: View
@Mock private lateinit var faceAuthInteractor: KeyguardFaceAuthInteractor
private lateinit var underTest: FaceAuthAccessibilityDelegate
@@ -55,14 +51,13 @@
underTest =
FaceAuthAccessibilityDelegate(
context.resources,
- keyguardUpdateMonitor,
faceAuthInteractor,
)
}
@Test
fun shouldListenForFaceTrue_onInitializeAccessibilityNodeInfo_clickActionAdded() {
- whenever(keyguardUpdateMonitor.shouldListenForFace()).thenReturn(true)
+ whenever(faceAuthInteractor.canFaceAuthRun()).thenReturn(true)
// WHEN node is initialized
val mockedNodeInfo = mock(AccessibilityNodeInfo::class.java)
@@ -81,7 +76,7 @@
@Test
fun shouldListenForFaceFalse_onInitializeAccessibilityNodeInfo_clickActionNotAdded() {
- whenever(keyguardUpdateMonitor.shouldListenForFace()).thenReturn(false)
+ whenever(faceAuthInteractor.canFaceAuthRun()).thenReturn(false)
// WHEN node is initialized
val mockedNodeInfo = mock(AccessibilityNodeInfo::class.java)
@@ -94,7 +89,7 @@
@Test
fun performAccessibilityAction_actionClick_retriesFaceAuth() {
- whenever(keyguardUpdateMonitor.shouldListenForFace()).thenReturn(true)
+ whenever(faceAuthInteractor.canFaceAuthRun()).thenReturn(true)
// WHEN click action is performed
underTest.performAccessibilityAction(
@@ -103,9 +98,6 @@
null
)
- // THEN retry face auth
- verify(keyguardUpdateMonitor)
- .requestFaceAuth(eq(FaceAuthApiRequestReason.ACCESSIBILITY_ACTION))
verify(faceAuthInteractor).onAccessibilityAction()
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerWithCoroutinesTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerWithCoroutinesTest.kt
index 9bff88b..79f0625 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerWithCoroutinesTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerWithCoroutinesTest.kt
@@ -34,6 +34,7 @@
import com.android.systemui.keyguard.data.repository.BiometricSettingsRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
import com.android.systemui.keyguard.data.repository.FakeTrustRepository
+import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractorFactory
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionState
@@ -106,6 +107,7 @@
FakeTrustRepository(),
testScope.backgroundScope,
mSelectedUserInteractor,
+ mock(KeyguardFaceAuthInteractor::class.java),
)
mAlternateBouncerInteractor =
AlternateBouncerInteractor(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractorTest.kt
index 0d44ed3..f0d26b6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractorTest.kt
@@ -67,6 +67,13 @@
)
biometricSettingsRepository = FakeBiometricSettingsRepository()
fingerprintPropertyRepository = FakeFingerprintPropertyRepository()
+
+ mSetFlagsRule.disableFlags(Flags.FLAG_DEVICE_ENTRY_UDFPS_REFACTOR)
+ initializeUnderTest()
+ }
+
+ private fun initializeUnderTest() {
+ // Set any feature flags before creating the alternateBouncerInteractor
underTest =
AlternateBouncerInteractor(
statusBarStateController,
@@ -161,6 +168,7 @@
@Test
fun canShowAlternateBouncerForFingerprint_rearFps() {
mSetFlagsRule.enableFlags(Flags.FLAG_DEVICE_ENTRY_UDFPS_REFACTOR)
+ initializeUnderTest()
givenCanShowAlternateBouncer()
fingerprintPropertyRepository.supportsRearFps() // does not support alternate bouncer
@@ -169,7 +177,7 @@
@Test
fun alternateBouncerUiAvailable_fromMultipleSources() {
- mSetFlagsRule.disableFlags(Flags.FLAG_DEVICE_ENTRY_UDFPS_REFACTOR)
+ initializeUnderTest()
assertFalse(bouncerRepository.alternateBouncerUIAvailable.value)
// GIVEN there are two different sources indicating the alternate bouncer is available
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerMessageInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerMessageInteractorTest.kt
index b48bc1d2..094616f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerMessageInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerMessageInteractorTest.kt
@@ -43,6 +43,7 @@
import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFaceAuthRepository
import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFingerprintAuthRepository
import com.android.systemui.keyguard.data.repository.FakeTrustRepository
+import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor
import com.android.systemui.keyguard.shared.model.AuthenticationFlags
import com.android.systemui.res.R.string.kg_too_many_failed_attempts_countdown
import com.android.systemui.res.R.string.kg_trust_agent_disabled
@@ -62,6 +63,7 @@
import org.mockito.ArgumentMatchers.eq
import org.mockito.Mock
import org.mockito.Mockito
+import org.mockito.Mockito.mock
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
@@ -122,6 +124,7 @@
fakeTrustRepository,
testScope.backgroundScope,
mSelectedUserInteractor,
+ mock(KeyguardFaceAuthInteractor::class.java),
)
underTest =
BouncerMessageInteractor(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractorTest.kt
index d6aa9ac..37a093e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractorTest.kt
@@ -16,7 +16,6 @@
package com.android.systemui.bouncer.domain.interactor
-import android.hardware.biometrics.BiometricSourceType
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
import android.testing.TestableResources
@@ -35,6 +34,7 @@
import com.android.systemui.classifier.FalsingCollector
import com.android.systemui.keyguard.DismissCallbackRegistry
import com.android.systemui.keyguard.data.repository.FakeTrustRepository
+import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.res.R
import com.android.systemui.statusbar.policy.KeyguardStateController
@@ -72,6 +72,7 @@
@Mock private lateinit var dismissCallbackRegistry: DismissCallbackRegistry
@Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
@Mock private lateinit var mSelectedUserInteractor: SelectedUserInteractor
+ @Mock private lateinit var faceAuthInteractor: KeyguardFaceAuthInteractor
private lateinit var mainHandler: FakeHandler
private lateinit var underTest: PrimaryBouncerInteractor
private lateinit var resources: TestableResources
@@ -103,6 +104,7 @@
trustRepository,
testScope.backgroundScope,
mSelectedUserInteractor,
+ faceAuthInteractor,
)
whenever(repository.primaryBouncerStartingDisappearAnimation.value).thenReturn(null)
whenever(repository.primaryBouncerShow.value).thenReturn(false)
@@ -423,10 +425,7 @@
mainHandler.setMode(FakeHandler.Mode.QUEUEING)
// GIVEN bouncer should be delayed due to face auth
- whenever(keyguardStateController.isFaceEnrolled).thenReturn(true)
- whenever(keyguardUpdateMonitor.isUnlockingWithBiometricAllowed(BiometricSourceType.FACE))
- .thenReturn(true)
- whenever(keyguardUpdateMonitor.doesCurrentPostureAllowFaceAuth()).thenReturn(true)
+ whenever(faceAuthInteractor.canFaceAuthRun()).thenReturn(true)
// WHEN bouncer show is requested
underTest.show(true)
@@ -444,15 +443,12 @@
}
@Test
- fun noDelayBouncer_biometricsAllowed_postureDoesNotAllowFaceAuth() {
+ fun noDelayBouncer_faceAuthNotAllowed() {
mainHandler.setMode(FakeHandler.Mode.QUEUEING)
// GIVEN bouncer should not be delayed because device isn't in the right posture for
// face auth
- whenever(keyguardStateController.isFaceEnrolled).thenReturn(true)
- whenever(keyguardUpdateMonitor.isUnlockingWithBiometricAllowed(BiometricSourceType.FACE))
- .thenReturn(true)
- whenever(keyguardUpdateMonitor.doesCurrentPostureAllowFaceAuth()).thenReturn(false)
+ whenever(faceAuthInteractor.canFaceAuthRun()).thenReturn(false)
// WHEN bouncer show is requested
underTest.show(true)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractorWithCoroutinesTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractorWithCoroutinesTest.kt
index d1b120e..bdf5041 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractorWithCoroutinesTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractorWithCoroutinesTest.kt
@@ -28,6 +28,7 @@
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.keyguard.DismissCallbackRegistry
import com.android.systemui.keyguard.data.repository.TrustRepository
+import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.user.domain.interactor.SelectedUserInteractor
import com.android.systemui.utils.os.FakeHandler
@@ -53,6 +54,7 @@
@Mock private lateinit var dismissCallbackRegistry: DismissCallbackRegistry
@Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
@Mock private lateinit var mSelectedUserInteractor: SelectedUserInteractor
+ @Mock private lateinit var faceAuthInteractor: KeyguardFaceAuthInteractor
private val mainHandler = FakeHandler(Looper.getMainLooper())
private lateinit var underTest: PrimaryBouncerInteractor
@@ -75,6 +77,7 @@
Mockito.mock(TrustRepository::class.java),
TestScope().backgroundScope,
mSelectedUserInteractor,
+ faceAuthInteractor,
)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/KeyguardBouncerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/KeyguardBouncerViewModelTest.kt
index 2cc8f0a..90e0c19 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/KeyguardBouncerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/KeyguardBouncerViewModelTest.kt
@@ -32,6 +32,7 @@
import com.android.systemui.coroutines.collectValues
import com.android.systemui.keyguard.DismissCallbackRegistry
import com.android.systemui.keyguard.data.repository.TrustRepository
+import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.user.domain.interactor.SelectedUserInteractor
import com.android.systemui.utils.os.FakeHandler
@@ -61,6 +62,7 @@
@Mock private lateinit var dismissCallbackRegistry: DismissCallbackRegistry
@Mock private lateinit var mSelectedUserInteractor: SelectedUserInteractor
@Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
+ @Mock private lateinit var faceAuthInteractor: KeyguardFaceAuthInteractor
lateinit var bouncerInteractor: PrimaryBouncerInteractor
private val mainHandler = FakeHandler(Looper.getMainLooper())
@@ -86,6 +88,7 @@
Mockito.mock(TrustRepository::class.java),
TestScope().backgroundScope,
mSelectedUserInteractor,
+ faceAuthInteractor,
)
underTest = KeyguardBouncerViewModel(bouncerView, bouncerInteractor)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt
index 6c990e45..40c9432 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt
@@ -30,7 +30,6 @@
import android.view.SurfaceControlViewHost
import androidx.test.filters.SmallTest
import com.android.internal.widget.LockPatternUtils
-import com.android.systemui.res.R
import com.android.systemui.SystemUIAppComponentFactoryBase
import com.android.systemui.SysuiTestCase
import com.android.systemui.animation.DialogLaunchAnimator
@@ -51,6 +50,7 @@
import com.android.systemui.keyguard.ui.preview.KeyguardPreviewRendererFactory
import com.android.systemui.keyguard.ui.preview.KeyguardRemotePreviewManager
import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.res.R
import com.android.systemui.settings.UserFileManager
import com.android.systemui.settings.UserTracker
import com.android.systemui.shared.customization.data.content.CustomizationProviderContract as Contract
@@ -173,7 +173,6 @@
FakeFeatureFlags().apply {
set(Flags.LOCKSCREEN_CUSTOM_CLOCKS, true)
set(Flags.WALLPAPER_FULLSCREEN_PREVIEW, true)
- set(Flags.FACE_AUTH_REFACTOR, true)
}
underTest.interactor =
KeyguardQuickAffordanceInteractor(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ResourceTrimmerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ResourceTrimmerTest.kt
index f0ff77e..852f9a5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ResourceTrimmerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ResourceTrimmerTest.kt
@@ -52,7 +52,6 @@
MockitoAnnotations.initMocks(this)
featureFlags.set(Flags.TRIM_RESOURCES_WITH_BACKGROUND_TRIM_AT_LOCK, true)
featureFlags.set(Flags.TRIM_FONT_CACHES_AT_UNLOCK, true)
- featureFlags.set(Flags.FACE_AUTH_REFACTOR, false)
powerInteractor = PowerInteractorFactory.create().powerInteractor
keyguardRepository.setDozeAmount(0f)
keyguardRepository.setKeyguardGoingAway(false)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt
index 0b148d1..45aca17 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt
@@ -58,7 +58,6 @@
import com.android.systemui.dump.DumpManager
import com.android.systemui.dump.logcatLogBuffer
import com.android.systemui.flags.FakeFeatureFlags
-import com.android.systemui.flags.Flags.FACE_AUTH_REFACTOR
import com.android.systemui.flags.Flags.KEYGUARD_WM_STATE_REFACTOR
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory
@@ -188,11 +187,7 @@
biometricSettingsRepository = FakeBiometricSettingsRepository()
deviceEntryFingerprintAuthRepository = FakeDeviceEntryFingerprintAuthRepository()
trustRepository = FakeTrustRepository()
- featureFlags =
- FakeFeatureFlags().apply {
- set(FACE_AUTH_REFACTOR, true)
- set(KEYGUARD_WM_STATE_REFACTOR, false)
- }
+ featureFlags = FakeFeatureFlags().apply { set(KEYGUARD_WM_STATE_REFACTOR, false) }
powerRepository = FakePowerRepository()
powerInteractor =
@@ -790,21 +785,19 @@
}
@Test
- fun everythingWorksWithFaceAuthRefactorFlagDisabled() =
+ fun everythingEmitsADefaultValueAndDoesNotErrorOut() =
testScope.runTest {
- featureFlags.set(FACE_AUTH_REFACTOR, false)
-
underTest = createDeviceEntryFaceAuthRepositoryImpl()
initCollectors()
// Collecting any flows exposed in the public API doesn't throw any error
- authStatus()
- detectStatus()
- authRunning()
- bypassEnabled()
- lockedOut()
- canFaceAuthRun()
- authenticated()
+ assertThat(authStatus()).isNull()
+ assertThat(detectStatus()).isNull()
+ assertThat(authRunning()).isNotNull()
+ assertThat(bypassEnabled()).isNotNull()
+ assertThat(lockedOut()).isNotNull()
+ assertThat(canFaceAuthRun()).isNotNull()
+ assertThat(authenticated()).isNotNull()
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt
index f2de8ca..b3e8fed 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt
@@ -41,8 +41,6 @@
import com.android.systemui.classifier.FalsingCollector
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.dump.logcatLogBuffer
-import com.android.systemui.flags.FakeFeatureFlags
-import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.DismissCallbackRegistry
import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository
import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFaceAuthRepository
@@ -109,8 +107,6 @@
val scheduler = TestCoroutineScheduler()
val dispatcher = StandardTestDispatcher(scheduler)
testScope = TestScope(dispatcher)
- val featureFlags = FakeFeatureFlags()
- featureFlags.set(Flags.FACE_AUTH_REFACTOR, true)
bouncerRepository = FakeKeyguardBouncerRepository()
faceAuthRepository = FakeDeviceEntryFaceAuthRepository()
keyguardTransitionRepository = FakeKeyguardTransitionRepository()
@@ -135,21 +131,24 @@
testScope.backgroundScope,
dispatcher,
faceAuthRepository,
- PrimaryBouncerInteractor(
- bouncerRepository,
- mock(BouncerView::class.java),
- mock(Handler::class.java),
- mock(KeyguardStateController::class.java),
- mock(KeyguardSecurityModel::class.java),
- mock(PrimaryBouncerCallbackInteractor::class.java),
- mock(FalsingCollector::class.java),
- mock(DismissCallbackRegistry::class.java),
- context,
- keyguardUpdateMonitor,
- FakeTrustRepository(),
- testScope.backgroundScope,
- mSelectedUserInteractor,
- ),
+ {
+ PrimaryBouncerInteractor(
+ bouncerRepository,
+ mock(BouncerView::class.java),
+ mock(Handler::class.java),
+ mock(KeyguardStateController::class.java),
+ mock(KeyguardSecurityModel::class.java),
+ mock(PrimaryBouncerCallbackInteractor::class.java),
+ mock(FalsingCollector::class.java),
+ mock(DismissCallbackRegistry::class.java),
+ context,
+ keyguardUpdateMonitor,
+ FakeTrustRepository(),
+ testScope.backgroundScope,
+ mSelectedUserInteractor,
+ underTest,
+ )
+ },
AlternateBouncerInteractor(
mock(StatusBarStateController::class.java),
mock(KeyguardStateController::class.java),
@@ -161,7 +160,6 @@
testScope.backgroundScope,
),
keyguardTransitionInteractor,
- featureFlags,
FaceAuthenticationLogger(logcatLogBuffer("faceAuthBuffer")),
keyguardUpdateMonitor,
fakeDeviceEntryFingerprintAuthRepository,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt
index ad2ec72..706f94e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt
@@ -24,8 +24,6 @@
import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository
import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository
import com.android.systemui.coroutines.collectLastValue
-import com.android.systemui.flags.FakeFeatureFlagsClassic
-import com.android.systemui.flags.Flags.FACE_AUTH_REFACTOR
import com.android.systemui.keyguard.data.repository.FakeCommandQueue
import com.android.systemui.keyguard.shared.model.CameraLaunchSourceModel
import com.android.systemui.power.domain.interactor.PowerInteractorFactory
@@ -54,7 +52,6 @@
private val repository = testUtils.keyguardRepository
private val sceneInteractor = testUtils.sceneInteractor()
private val commandQueue = FakeCommandQueue()
- private val featureFlags = FakeFeatureFlagsClassic().apply { set(FACE_AUTH_REFACTOR, true) }
private val bouncerRepository = FakeKeyguardBouncerRepository()
private val configurationRepository = FakeConfigurationRepository()
private val shadeRepository = FakeShadeRepository()
@@ -66,7 +63,6 @@
repository = repository,
commandQueue = commandQueue,
powerInteractor = PowerInteractorFactory.create().powerInteractor,
- featureFlags = featureFlags,
sceneContainerFlags = testUtils.sceneContainerFlags,
bouncerRepository = bouncerRepository,
configurationRepository = configurationRepository,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorParameterizedTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorParameterizedTest.kt
index fe474fa..66c8a22 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorParameterizedTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorParameterizedTest.kt
@@ -31,7 +31,6 @@
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.dock.DockManagerFake
import com.android.systemui.flags.FakeFeatureFlags
-import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.data.quickaffordance.BuiltInKeyguardQuickAffordanceKeys
import com.android.systemui.keyguard.data.quickaffordance.FakeKeyguardQuickAffordanceConfig
import com.android.systemui.keyguard.data.quickaffordance.FakeKeyguardQuickAffordanceProviderClientFactory
@@ -302,10 +301,7 @@
dumpManager = mock(),
userHandle = UserHandle.SYSTEM,
)
- val featureFlags =
- FakeFeatureFlags().apply {
- set(Flags.FACE_AUTH_REFACTOR, true)
- }
+ val featureFlags = FakeFeatureFlags()
val testDispatcher = StandardTestDispatcher()
testScope = TestScope(testDispatcher)
underTest =
@@ -357,7 +353,7 @@
}
underTest.onQuickAffordanceTriggered(
- configKey = "${KeyguardQuickAffordancePosition.BOTTOM_START.toSlotId()}::${key}",
+ configKey = "${KeyguardQuickAffordancePosition.BOTTOM_START.toSlotId()}::$key",
expandable = expandable,
slotId = "",
)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt
index 347d580..bc4bae0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt
@@ -22,7 +22,6 @@
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.internal.widget.LockPatternUtils
-import com.android.systemui.res.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.animation.DialogLaunchAnimator
import com.android.systemui.common.shared.model.ContentDescription
@@ -31,7 +30,6 @@
import com.android.systemui.dock.DockManager
import com.android.systemui.dock.DockManagerFake
import com.android.systemui.flags.FakeFeatureFlags
-import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.data.quickaffordance.BuiltInKeyguardQuickAffordanceKeys
import com.android.systemui.keyguard.data.quickaffordance.FakeKeyguardQuickAffordanceConfig
import com.android.systemui.keyguard.data.quickaffordance.FakeKeyguardQuickAffordanceProviderClientFactory
@@ -48,6 +46,7 @@
import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordancePosition
import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordancesMetricsLogger
import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.res.R
import com.android.systemui.settings.UserFileManager
import com.android.systemui.settings.UserTracker
import com.android.systemui.shared.keyguard.shared.model.KeyguardQuickAffordanceSlots
@@ -102,9 +101,11 @@
overrideResource(
R.array.config_keyguardQuickAffordanceDefaults,
arrayOf(
- KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START + ":" +
+ KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START +
+ ":" +
BuiltInKeyguardQuickAffordanceKeys.HOME_CONTROLS,
- KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_END + ":" +
+ KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_END +
+ ":" +
BuiltInKeyguardQuickAffordanceKeys.QUICK_ACCESS_WALLET
)
)
@@ -168,10 +169,7 @@
dumpManager = mock(),
userHandle = UserHandle.SYSTEM,
)
- featureFlags =
- FakeFeatureFlags().apply {
- set(Flags.FACE_AUTH_REFACTOR, true)
- }
+ featureFlags = FakeFeatureFlags()
val withDeps =
KeyguardInteractorFactory.create(
@@ -216,9 +214,8 @@
assertThat(collectedValue())
.isInstanceOf(KeyguardQuickAffordanceModel.Visible::class.java)
val visibleModel = collectedValue() as KeyguardQuickAffordanceModel.Visible
- assertThat(visibleModel.configKey).isEqualTo(
- "${KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START}::${configKey}"
- )
+ assertThat(visibleModel.configKey)
+ .isEqualTo("${KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START}::$configKey")
assertThat(visibleModel.icon).isEqualTo(ICON)
assertThat(visibleModel.icon.contentDescription)
.isEqualTo(ContentDescription.Resource(res = CONTENT_DESCRIPTION_RESOURCE_ID))
@@ -243,9 +240,8 @@
assertThat(collectedValue())
.isInstanceOf(KeyguardQuickAffordanceModel.Visible::class.java)
val visibleModel = collectedValue() as KeyguardQuickAffordanceModel.Visible
- assertThat(visibleModel.configKey).isEqualTo(
- "${KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_END}::${configKey}"
- )
+ assertThat(visibleModel.configKey)
+ .isEqualTo("${KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_END}::$configKey")
assertThat(visibleModel.icon).isEqualTo(ICON)
assertThat(visibleModel.icon.contentDescription)
.isEqualTo(ContentDescription.Resource(res = CONTENT_DESCRIPTION_RESOURCE_ID))
@@ -364,9 +360,8 @@
assertThat(collectedValue())
.isInstanceOf(KeyguardQuickAffordanceModel.Visible::class.java)
val visibleModel = collectedValue() as KeyguardQuickAffordanceModel.Visible
- assertThat(visibleModel.configKey).isEqualTo(
- "${KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START}::${configKey}"
- )
+ assertThat(visibleModel.configKey)
+ .isEqualTo("${KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START}::$configKey")
assertThat(visibleModel.icon).isEqualTo(ICON)
assertThat(visibleModel.icon.contentDescription)
.isEqualTo(ContentDescription.Resource(res = CONTENT_DESCRIPTION_RESOURCE_ID))
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
index bf23bf8..bf6d5c4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
@@ -121,11 +121,7 @@
whenever(keyguardSecurityModel.getSecurityMode(anyInt())).thenReturn(PIN)
- featureFlags =
- FakeFeatureFlags().apply {
- set(Flags.FACE_AUTH_REFACTOR, true)
- set(Flags.KEYGUARD_WM_STATE_REFACTOR, false)
- }
+ featureFlags = FakeFeatureFlags().apply { set(Flags.KEYGUARD_WM_STATE_REFACTOR, false) }
keyguardInteractor = createKeyguardInteractor()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/OccludingAppDeviceEntryInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/OccludingAppDeviceEntryInteractorTest.kt
index 91e1705..1f245f1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/OccludingAppDeviceEntryInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/OccludingAppDeviceEntryInteractorTest.kt
@@ -32,7 +32,6 @@
import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.flags.FakeFeatureFlags
-import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository
import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFingerprintAuthRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
@@ -103,7 +102,7 @@
keyguardRepository = FakeKeyguardRepository()
bouncerRepository = FakeKeyguardBouncerRepository()
configurationRepository = FakeConfigurationRepository()
- featureFlags = FakeFeatureFlags().apply { set(Flags.FACE_AUTH_REFACTOR, false) }
+ featureFlags = FakeFeatureFlags()
trustRepository = FakeTrustRepository()
powerRepository = FakePowerRepository()
powerInteractor =
@@ -147,7 +146,8 @@
keyguardUpdateMonitor,
trustRepository,
testScope.backgroundScope,
- mSelectedUserInteractor
+ mSelectedUserInteractor,
+ keyguardFaceAuthInteractor = mock(),
),
AlternateBouncerInteractor(
statusBarStateController = mock(),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/UdfpsKeyguardInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/UdfpsKeyguardInteractorTest.kt
index 16d072e..87eee1a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/UdfpsKeyguardInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/UdfpsKeyguardInteractorTest.kt
@@ -25,8 +25,6 @@
import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.doze.util.BurnInHelperWrapper
-import com.android.systemui.flags.FakeFeatureFlags
-import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.data.repository.FakeCommandQueue
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.keyguard.shared.model.StatusBarState
@@ -64,7 +62,6 @@
private lateinit var bouncerRepository: KeyguardBouncerRepository
private lateinit var keyguardRepository: FakeKeyguardRepository
private lateinit var fakeCommandQueue: FakeCommandQueue
- private lateinit var featureFlags: FakeFeatureFlags
private lateinit var burnInInteractor: BurnInInteractor
private lateinit var shadeRepository: FakeShadeRepository
private lateinit var keyguardInteractor: KeyguardInteractor
@@ -80,8 +77,7 @@
MockitoAnnotations.initMocks(this)
testScope = TestScope()
configRepository = FakeConfigurationRepository()
- featureFlags = FakeFeatureFlags().apply { set(Flags.FACE_AUTH_REFACTOR, false) }
- KeyguardInteractorFactory.create(featureFlags = featureFlags).let {
+ KeyguardInteractorFactory.create().let {
keyguardInteractor = it.keyguardInteractor
keyguardRepository = it.repository
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprintTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprintTest.kt
index 15a1782..740fce9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprintTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprintTest.kt
@@ -30,7 +30,7 @@
import com.android.systemui.keyguard.ui.view.layout.items.ClockSection
import com.android.systemui.keyguard.ui.view.layout.sections.AodBurnInSection
import com.android.systemui.keyguard.ui.view.layout.sections.AodNotificationIconsSection
-import com.android.systemui.keyguard.ui.view.layout.sections.DefaultDeviceEntryIconSection
+import com.android.systemui.keyguard.ui.view.layout.sections.DefaultDeviceEntrySection
import com.android.systemui.keyguard.ui.view.layout.sections.DefaultIndicationAreaSection
import com.android.systemui.keyguard.ui.view.layout.sections.DefaultNotificationStackScrollLayoutSection
import com.android.systemui.keyguard.ui.view.layout.sections.DefaultSettingsPopupMenuSection
@@ -57,7 +57,7 @@
private lateinit var underTest: DefaultKeyguardBlueprint
private lateinit var rootView: KeyguardRootView
@Mock private lateinit var defaultIndicationAreaSection: DefaultIndicationAreaSection
- @Mock private lateinit var mDefaultDeviceEntryIconSection: DefaultDeviceEntryIconSection
+ @Mock private lateinit var mDefaultDeviceEntrySection: DefaultDeviceEntrySection
@Mock private lateinit var defaultShortcutsSection: DefaultShortcutsSection
@Mock private lateinit var defaultAmbientIndicationAreaSection: Optional<KeyguardSection>
@Mock private lateinit var defaultSettingsPopupMenuSection: DefaultSettingsPopupMenuSection
@@ -78,7 +78,7 @@
underTest =
DefaultKeyguardBlueprint(
defaultIndicationAreaSection,
- mDefaultDeviceEntryIconSection,
+ mDefaultDeviceEntrySection,
defaultShortcutsSection,
defaultAmbientIndicationAreaSection,
defaultSettingsPopupMenuSection,
@@ -105,14 +105,14 @@
val prevBlueprint = mock(KeyguardBlueprint::class.java)
val someSection = mock(KeyguardSection::class.java)
whenever(prevBlueprint.sections)
- .thenReturn(underTest.sections.minus(mDefaultDeviceEntryIconSection).plus(someSection))
+ .thenReturn(underTest.sections.minus(mDefaultDeviceEntrySection).plus(someSection))
val constraintLayout = ConstraintLayout(context, null)
underTest.replaceViews(prevBlueprint, constraintLayout)
- underTest.sections.minus(mDefaultDeviceEntryIconSection).forEach {
+ underTest.sections.minus(mDefaultDeviceEntrySection).forEach {
verify(it, never())?.addViews(constraintLayout)
}
- verify(mDefaultDeviceEntryIconSection).addViews(constraintLayout)
+ verify(mDefaultDeviceEntrySection).addViews(constraintLayout)
verify(someSection).removeViews(constraintLayout)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntryIconSectionTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySectionTest.kt
similarity index 94%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntryIconSectionTest.kt
rename to packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySectionTest.kt
index d976045..67fba42 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntryIconSectionTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySectionTest.kt
@@ -30,6 +30,7 @@
import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.flags.FakeFeatureFlagsClassic
import com.android.systemui.flags.Flags
+import com.android.systemui.keyguard.ui.SwipeUpAnywhereGestureHandler
import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerViewModel
import com.android.systemui.keyguard.ui.viewmodel.DeviceEntryBackgroundViewModel
import com.android.systemui.keyguard.ui.viewmodel.DeviceEntryForegroundViewModel
@@ -38,6 +39,7 @@
import com.android.systemui.res.R
import com.android.systemui.shade.NotificationPanelView
import com.android.systemui.statusbar.NotificationShadeWindowController
+import com.android.systemui.statusbar.gesture.TapGestureDetector
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.TestScope
@@ -53,7 +55,7 @@
@ExperimentalCoroutinesApi
@RunWith(JUnit4::class)
@SmallTest
-class DefaultDeviceEntryIconSectionTest : SysuiTestCase() {
+class DefaultDeviceEntrySectionTest : SysuiTestCase() {
@Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
@Mock private lateinit var authController: AuthController
@Mock(answer = Answers.RETURNS_DEEP_STUBS) private lateinit var windowManager: WindowManager
@@ -61,7 +63,7 @@
private lateinit var featureFlags: FakeFeatureFlags
@Mock private lateinit var lockIconViewController: LockIconViewController
@Mock private lateinit var falsingManager: FalsingManager
- private lateinit var underTest: DefaultDeviceEntryIconSection
+ private lateinit var underTest: DefaultDeviceEntrySection
@Before
fun setup() {
@@ -72,7 +74,7 @@
featureFlags =
FakeFeatureFlagsClassic().apply { set(Flags.LOCKSCREEN_ENABLE_LANDSCAPE, false) }
underTest =
- DefaultDeviceEntryIconSection(
+ DefaultDeviceEntrySection(
keyguardUpdateMonitor,
authController,
windowManager,
@@ -87,6 +89,8 @@
{ mock(AlternateBouncerViewModel::class.java) },
{ mock(NotificationShadeWindowController::class.java) },
TestScope().backgroundScope,
+ { mock(SwipeUpAnywhereGestureHandler::class.java) },
+ { mock(TapGestureDetector::class.java) },
)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerViewModelTest.kt
index 1768f8c..fc9f54ec 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerViewModelTest.kt
@@ -27,7 +27,6 @@
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionStep
-import com.android.systemui.plugins.FalsingManager
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
import com.google.common.collect.Range
import com.google.common.truth.Truth.assertThat
@@ -50,7 +49,6 @@
private lateinit var testScope: TestScope
@Mock private lateinit var statusBarKeyguardViewManager: StatusBarKeyguardViewManager
- @Mock private lateinit var falsingManager: FalsingManager
private lateinit var transitionRepository: FakeKeyguardTransitionRepository
private lateinit var transitionInteractor: KeyguardTransitionInteractor
@@ -69,7 +67,6 @@
AlternateBouncerViewModel(
statusBarKeyguardViewManager,
transitionInteractor,
- falsingManager,
)
}
@@ -106,36 +103,6 @@
}
@Test
- fun clickListenerUpdate() =
- runTest(UnconfinedTestDispatcher()) {
- val clickListener by collectLastValue(underTest.onClickListener)
-
- // keyguard state => ALTERNATE_BOUNCER
- transitionRepository.sendTransitionStep(
- stepToAlternateBouncer(0f, TransitionState.STARTED)
- )
- assertThat(clickListener).isNull()
- transitionRepository.sendTransitionStep(stepToAlternateBouncer(.3f))
- assertThat(clickListener).isNull()
- transitionRepository.sendTransitionStep(stepToAlternateBouncer(.6f))
- assertThat(clickListener).isNull()
- transitionRepository.sendTransitionStep(stepToAlternateBouncer(1f))
- assertThat(clickListener).isNotNull()
-
- // ALTERNATE_BOUNCER -> keyguard state
- transitionRepository.sendTransitionStep(
- stepFromAlternateBouncer(0f, TransitionState.STARTED)
- )
- assertThat(clickListener).isNotNull()
- transitionRepository.sendTransitionStep(stepFromAlternateBouncer(.3f))
- assertThat(clickListener).isNull()
- transitionRepository.sendTransitionStep(stepFromAlternateBouncer(.6f))
- assertThat(clickListener).isNull()
- transitionRepository.sendTransitionStep(stepFromAlternateBouncer(1f))
- assertThat(clickListener).isNull()
- }
-
- @Test
fun forcePluginOpen() =
runTest(UnconfinedTestDispatcher()) {
val forcePluginOpen by collectLastValue(underTest.forcePluginOpen)
@@ -156,6 +123,27 @@
assertThat(forcePluginOpen).isFalse()
}
+ @Test
+ fun registerForDismissGestures() =
+ runTest(UnconfinedTestDispatcher()) {
+ val registerForDismissGestures by collectLastValue(underTest.registerForDismissGestures)
+ transitionRepository.sendTransitionStep(
+ stepToAlternateBouncer(0f, TransitionState.STARTED)
+ )
+ transitionRepository.sendTransitionStep(stepToAlternateBouncer(.3f))
+ transitionRepository.sendTransitionStep(stepToAlternateBouncer(.6f))
+ transitionRepository.sendTransitionStep(stepToAlternateBouncer(1f))
+ assertThat(registerForDismissGestures).isTrue()
+
+ transitionRepository.sendTransitionStep(
+ stepFromAlternateBouncer(0f, TransitionState.STARTED)
+ )
+ transitionRepository.sendTransitionStep(stepFromAlternateBouncer(.3f))
+ transitionRepository.sendTransitionStep(stepFromAlternateBouncer(.6f))
+ transitionRepository.sendTransitionStep(stepFromAlternateBouncer(1f))
+ assertThat(registerForDismissGestures).isFalse()
+ }
+
private fun stepToAlternateBouncer(
value: Float,
state: TransitionState = TransitionState.RUNNING
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt
index 32d28a3..1584be0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt
@@ -22,7 +22,6 @@
import androidx.test.filters.SmallTest
import com.android.internal.logging.testing.UiEventLoggerFake
import com.android.internal.widget.LockPatternUtils
-import com.android.systemui.res.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.animation.DialogLaunchAnimator
import com.android.systemui.animation.Expandable
@@ -52,6 +51,7 @@
import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordancePosition
import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordancesMetricsLogger
import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.res.R
import com.android.systemui.settings.UserFileManager
import com.android.systemui.settings.UserTracker
import com.android.systemui.shared.keyguard.shared.model.KeyguardQuickAffordanceSlots
@@ -116,9 +116,11 @@
overrideResource(
R.array.config_keyguardQuickAffordanceDefaults,
arrayOf(
- KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START + ":" +
+ KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START +
+ ":" +
BuiltInKeyguardQuickAffordanceKeys.HOME_CONTROLS,
- KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_END + ":" +
+ KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_END +
+ ":" +
BuiltInKeyguardQuickAffordanceKeys.QUICK_ACCESS_WALLET
)
)
@@ -138,7 +140,6 @@
biometricSettingsRepository = FakeBiometricSettingsRepository()
val featureFlags =
FakeFeatureFlags().apply {
- set(Flags.FACE_AUTH_REFACTOR, true)
set(Flags.LOCK_SCREEN_LONG_PRESS_ENABLED, false)
set(Flags.LOCK_SCREEN_LONG_PRESS_DIRECT_TO_WPP, false)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordancesCombinedViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordancesCombinedViewModelTest.kt
index 25d1419..67c4e26 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordancesCombinedViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordancesCombinedViewModelTest.kt
@@ -22,14 +22,13 @@
import android.os.UserHandle
import androidx.test.filters.SmallTest
import com.android.internal.widget.LockPatternUtils
-import com.android.systemui.res.R
+import com.android.systemui.Flags as AConfigFlags
import com.android.systemui.SysuiTestCase
import com.android.systemui.animation.DialogLaunchAnimator
import com.android.systemui.animation.Expandable
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.dock.DockManagerFake
-import com.android.systemui.Flags as AConfigFlags
import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.data.quickaffordance.BuiltInKeyguardQuickAffordanceKeys
@@ -49,6 +48,7 @@
import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordancePosition
import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordancesMetricsLogger
import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.res.R
import com.android.systemui.settings.UserFileManager
import com.android.systemui.settings.UserTracker
import com.android.systemui.shared.keyguard.shared.model.KeyguardQuickAffordanceSlots
@@ -129,7 +129,6 @@
val featureFlags =
FakeFeatureFlags().apply {
- set(Flags.FACE_AUTH_REFACTOR, true)
set(Flags.LOCK_SCREEN_LONG_PRESS_ENABLED, false)
set(Flags.LOCK_SCREEN_LONG_PRESS_DIRECT_TO_WPP, false)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt
index a838684..e6d6cf2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt
@@ -32,9 +32,7 @@
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.deviceentry.data.repository.FakeDeviceEntryRepository
-import com.android.systemui.flags.FakeFeatureFlagsClassic
import com.android.systemui.flags.FakeFeatureFlagsClassicModule
-import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
import com.android.systemui.keyguard.domain.interactor.BurnInInteractor
@@ -109,9 +107,7 @@
mSetFlagsRule.enableFlags(AConfigFlags.FLAG_KEYGUARD_BOTTOM_AREA_REFACTOR)
- val featureFlags = FakeFeatureFlagsClassic().apply { set(Flags.FACE_AUTH_REFACTOR, true) }
-
- val withDeps = KeyguardInteractorFactory.create(featureFlags = featureFlags)
+ val withDeps = KeyguardInteractorFactory.create()
keyguardInteractor = withDeps.keyguardInteractor
repository = withDeps.repository
configurationRepository = withDeps.configurationRepository
@@ -135,7 +131,6 @@
deviceEntryInteractor =
mock { whenever(isBypassEnabled).thenReturn(MutableStateFlow(false)) },
dozeParameters = mock(),
- featureFlags,
keyguardInteractor,
keyguardTransitionInteractor,
notificationsKeyguardInteractor =
@@ -347,8 +342,7 @@
DaggerKeyguardRootViewModelTestWithFakes_TestComponent.factory()
.create(
test = this,
- featureFlags =
- FakeFeatureFlagsClassicModule { set(Flags.FACE_AUTH_REFACTOR, true) },
+ featureFlags = FakeFeatureFlagsClassicModule(),
mocks =
TestMocksModule(
dozeParameters = dozeParams,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToAodTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToAodTransitionViewModelTest.kt
index c50be04..2314c83 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToAodTransitionViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToAodTransitionViewModelTest.kt
@@ -28,7 +28,6 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.deviceentry.data.repository.FakeDeviceEntryRepository
import com.android.systemui.flags.FakeFeatureFlagsClassicModule
-import com.android.systemui.flags.Flags.FACE_AUTH_REFACTOR
import com.android.systemui.flags.Flags.FULL_SCREEN_USER_SWITCHER
import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
@@ -94,10 +93,7 @@
.create(
test = this,
featureFlags =
- FakeFeatureFlagsClassicModule {
- set(FACE_AUTH_REFACTOR, true)
- set(FULL_SCREEN_USER_SWITCHER, true)
- },
+ FakeFeatureFlagsClassicModule { set(FULL_SCREEN_USER_SWITCHER, true) },
mocks = TestMocksModule(),
)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModelTest.kt
index 26704da..baac513 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModelTest.kt
@@ -85,10 +85,7 @@
.create(
test = this,
featureFlags =
- FakeFeatureFlagsClassicModule {
- set(Flags.FACE_AUTH_REFACTOR, true)
- set(Flags.FULL_SCREEN_USER_SWITCHER, true)
- },
+ FakeFeatureFlagsClassicModule { set(Flags.FULL_SCREEN_USER_SWITCHER, true) },
mocks = TestMocksModule(),
)
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModelTest.kt
index ff3135a6..29d8f08 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModelTest.kt
@@ -85,10 +85,7 @@
.create(
test = this,
featureFlags =
- FakeFeatureFlagsClassicModule {
- set(Flags.FACE_AUTH_REFACTOR, true)
- set(Flags.FULL_SCREEN_USER_SWITCHER, true)
- },
+ FakeFeatureFlagsClassicModule { set(Flags.FULL_SCREEN_USER_SWITCHER, true) },
mocks = TestMocksModule(),
)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToPrimaryBouncerTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToPrimaryBouncerTransitionViewModelTest.kt
index 8afd8e4..049e4e2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToPrimaryBouncerTransitionViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToPrimaryBouncerTransitionViewModelTest.kt
@@ -86,10 +86,7 @@
.create(
test = this,
featureFlags =
- FakeFeatureFlagsClassicModule {
- set(Flags.FACE_AUTH_REFACTOR, true)
- set(Flags.FULL_SCREEN_USER_SWITCHER, true)
- },
+ FakeFeatureFlagsClassicModule { set(Flags.FULL_SCREEN_USER_SWITCHER, true) },
mocks = TestMocksModule(),
)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/UdfpsAodViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/UdfpsAodViewModelTest.kt
index 5058b16..6512290 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/UdfpsAodViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/UdfpsAodViewModelTest.kt
@@ -23,8 +23,6 @@
import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.doze.util.BurnInHelperWrapper
-import com.android.systemui.flags.FakeFeatureFlags
-import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.keyguard.domain.interactor.BurnInInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
@@ -54,7 +52,6 @@
private lateinit var configRepository: FakeConfigurationRepository
private lateinit var bouncerRepository: KeyguardBouncerRepository
private lateinit var keyguardRepository: FakeKeyguardRepository
- private lateinit var featureFlags: FakeFeatureFlags
private lateinit var shadeRepository: FakeShadeRepository
private lateinit var keyguardInteractor: KeyguardInteractor
@@ -67,16 +64,12 @@
overrideResource(com.android.systemui.res.R.dimen.lock_icon_padding, defaultPadding)
testScope = TestScope()
shadeRepository = FakeShadeRepository()
- featureFlags = FakeFeatureFlags().apply { set(Flags.FACE_AUTH_REFACTOR, false) }
- KeyguardInteractorFactory.create(
- featureFlags = featureFlags,
- )
- .also {
- keyguardInteractor = it.keyguardInteractor
- keyguardRepository = it.repository
- configRepository = it.configurationRepository
- bouncerRepository = it.bouncerRepository
- }
+ KeyguardInteractorFactory.create().also {
+ keyguardInteractor = it.keyguardInteractor
+ keyguardRepository = it.repository
+ configRepository = it.configurationRepository
+ bouncerRepository = it.bouncerRepository
+ }
val udfpsKeyguardInteractor =
UdfpsKeyguardInteractor(
configRepository,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/UdfpsFingerprintViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/UdfpsFingerprintViewModelTest.kt
index f039f53..95b2fe5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/UdfpsFingerprintViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/UdfpsFingerprintViewModelTest.kt
@@ -24,8 +24,6 @@
import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.doze.util.BurnInHelperWrapper
-import com.android.systemui.flags.FakeFeatureFlags
-import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.data.repository.FakeCommandQueue
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
@@ -59,7 +57,6 @@
private lateinit var bouncerRepository: KeyguardBouncerRepository
private lateinit var keyguardRepository: FakeKeyguardRepository
private lateinit var fakeCommandQueue: FakeCommandQueue
- private lateinit var featureFlags: FakeFeatureFlags
private lateinit var transitionRepository: FakeKeyguardTransitionRepository
private lateinit var shadeRepository: FakeShadeRepository
@@ -75,14 +72,12 @@
keyguardRepository = FakeKeyguardRepository()
bouncerRepository = FakeKeyguardBouncerRepository()
fakeCommandQueue = FakeCommandQueue()
- featureFlags = FakeFeatureFlags().apply { set(Flags.FACE_AUTH_REFACTOR, false) }
bouncerRepository = FakeKeyguardBouncerRepository()
transitionRepository = FakeKeyguardTransitionRepository()
shadeRepository = FakeShadeRepository()
val keyguardInteractor =
KeyguardInteractorFactory.create(
repository = keyguardRepository,
- featureFlags = featureFlags,
)
.keyguardInteractor
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/UdfpsLockscreenViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/UdfpsLockscreenViewModelTest.kt
index c1805db..848a94b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/UdfpsLockscreenViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/UdfpsLockscreenViewModelTest.kt
@@ -23,8 +23,6 @@
import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository
import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository
import com.android.systemui.coroutines.collectLastValue
-import com.android.systemui.flags.FakeFeatureFlags
-import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
import com.android.systemui.keyguard.domain.interactor.BurnInInteractor
@@ -75,7 +73,6 @@
private lateinit var keyguardInteractor: KeyguardInteractor
private lateinit var bouncerRepository: FakeKeyguardBouncerRepository
private lateinit var shadeRepository: FakeShadeRepository
- private lateinit var featureFlags: FakeFeatureFlags
@Before
fun setUp() {
@@ -83,16 +80,12 @@
testScope = TestScope()
transitionRepository = FakeKeyguardTransitionRepository()
shadeRepository = FakeShadeRepository()
- featureFlags = FakeFeatureFlags().apply { set(Flags.FACE_AUTH_REFACTOR, false) }
- KeyguardInteractorFactory.create(
- featureFlags = featureFlags,
- )
- .also {
- keyguardInteractor = it.keyguardInteractor
- keyguardRepository = it.repository
- configRepository = it.configurationRepository
- bouncerRepository = it.bouncerRepository
- }
+ KeyguardInteractorFactory.create().also {
+ keyguardInteractor = it.keyguardInteractor
+ keyguardRepository = it.repository
+ configRepository = it.configurationRepository
+ bouncerRepository = it.bouncerRepository
+ }
val transitionInteractor =
KeyguardTransitionInteractorFactory.create(
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 722fb2c..36b4435 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
@@ -31,7 +31,6 @@
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyFloat;
import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.clearInvocations;
@@ -56,7 +55,6 @@
import androidx.constraintlayout.widget.ConstraintSet;
import androidx.test.filters.SmallTest;
-import com.android.keyguard.FaceAuthApiRequestReason;
import com.android.systemui.DejankUtils;
import com.android.systemui.flags.Flags;
import com.android.systemui.keyguard.shared.KeyguardShadeMigrationNssl;
@@ -1075,33 +1073,6 @@
mEmptySpaceClickListenerCaptor.getValue().onEmptySpaceClicked(0, 0);
verify(mKeyguardFaceAuthInteractor).onNotificationPanelClicked();
- verify(mUpdateMonitor).requestFaceAuth(
- FaceAuthApiRequestReason.NOTIFICATION_PANEL_CLICKED);
- }
-
- @Test
- public void onEmptySpaceClicked_whenDozingAndOnKeyguard_doesNotRequestFaceAuth() {
- StatusBarStateController.StateListener statusBarStateListener =
- mNotificationPanelViewController.getStatusBarStateListener();
- statusBarStateListener.onStateChanged(KEYGUARD);
- mNotificationPanelViewController.setDozing(true, false);
-
- // This sets the dozing state that is read when onMiddleClicked is eventually invoked.
- mTouchHandler.onTouch(mock(View.class), mDownMotionEvent);
- mEmptySpaceClickListenerCaptor.getValue().onEmptySpaceClicked(0, 0);
-
- verify(mUpdateMonitor, never()).requestFaceAuth(anyString());
- }
-
- @Test
- public void onEmptySpaceClicked_whenStatusBarShadeLocked_doesNotRequestFaceAuth() {
- StatusBarStateController.StateListener statusBarStateListener =
- mNotificationPanelViewController.getStatusBarStateListener();
- statusBarStateListener.onStateChanged(SHADE_LOCKED);
-
- mEmptySpaceClickListenerCaptor.getValue().onEmptySpaceClicked(0, 0);
-
- verify(mUpdateMonitor, never()).requestFaceAuth(anyString());
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java
index 8403ac5..39b306b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java
@@ -188,7 +188,6 @@
keyguardRepository,
new FakeCommandQueue(),
powerInteractor,
- featureFlags,
sceneContainerFlags,
new FakeKeyguardBouncerRepository(),
configurationRepository,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
index d89491c..0587633 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
@@ -65,6 +65,7 @@
import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFaceAuthRepository
import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFingerprintAuthRepository
import com.android.systemui.keyguard.data.repository.FakeTrustRepository
+import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.shared.KeyguardShadeMigrationNssl
import com.android.systemui.keyguard.shared.model.TransitionStep
@@ -97,6 +98,7 @@
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
+import java.util.Optional
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.emptyFlow
import kotlinx.coroutines.test.TestScope
@@ -111,9 +113,8 @@
import org.mockito.Mockito.never
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
-import org.mockito.MockitoAnnotations
-import java.util.Optional
import org.mockito.Mockito.`when` as whenever
+import org.mockito.MockitoAnnotations
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@@ -265,6 +266,7 @@
FakeTrustRepository(),
testScope.backgroundScope,
mSelectedUserInteractor,
+ mock(KeyguardFaceAuthInteractor::class.java)
),
facePropertyRepository = FakeFacePropertyRepository(),
deviceEntryFingerprintAuthRepository =
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 9c8816c..29b1366 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
@@ -251,6 +251,7 @@
FakeTrustRepository(),
testScope.backgroundScope,
mSelectedUserInteractor,
+ mock(),
),
facePropertyRepository = FakeFacePropertyRepository(),
deviceEntryFingerprintAuthRepository =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerBaseTest.java
index bff47f1..1dbb297 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerBaseTest.java
@@ -224,7 +224,6 @@
mKeyguardRepository,
new FakeCommandQueue(),
powerInteractor,
- featureFlags,
sceneContainerFlags,
new FakeKeyguardBouncerRepository(),
configurationRepository,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImplTest.kt
index 61e4370..65e0fa1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImplTest.kt
@@ -105,10 +105,7 @@
.create(
test = this,
featureFlags =
- FakeFeatureFlagsClassicModule {
- set(Flags.FACE_AUTH_REFACTOR, false)
- set(Flags.FULL_SCREEN_USER_SWITCHER, true)
- },
+ FakeFeatureFlagsClassicModule { set(Flags.FULL_SCREEN_USER_SWITCHER, true) },
mocks =
TestMocksModule(
dozeParameters = dozeParameters,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorLegacyImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorLegacyImplTest.kt
index 92eb6ed..6e6e438 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorLegacyImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorLegacyImplTest.kt
@@ -86,10 +86,7 @@
.create(
test = this,
featureFlags =
- FakeFeatureFlagsClassicModule {
- set(Flags.FACE_AUTH_REFACTOR, false)
- set(Flags.FULL_SCREEN_USER_SWITCHER, true)
- },
+ FakeFeatureFlagsClassicModule { set(Flags.FULL_SCREEN_USER_SWITCHER, true) },
mocks =
TestMocksModule(
dozeParameters = dozeParameters,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImplTest.kt
index 729f3f8..565e20a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImplTest.kt
@@ -91,10 +91,7 @@
.create(
test = this,
featureFlags =
- FakeFeatureFlagsClassicModule {
- set(Flags.FACE_AUTH_REFACTOR, false)
- set(Flags.FULL_SCREEN_USER_SWITCHER, true)
- },
+ FakeFeatureFlagsClassicModule { set(Flags.FULL_SCREEN_USER_SWITCHER, true) },
mocks =
TestMocksModule(
dozeParameters = dozeParameters,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerBaseTest.java
index 63e46d1..459040a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerBaseTest.java
@@ -18,7 +18,6 @@
import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_DEFAULT;
-import static com.android.systemui.flags.Flags.FACE_AUTH_REFACTOR;
import static com.android.systemui.flags.Flags.KEYGUARD_TALKBACK_FIX;
import static com.android.systemui.flags.Flags.LOCKSCREEN_WALLPAPER_DREAM_ENABLED;
import static com.android.systemui.keyguard.ScreenLifecycle.SCREEN_ON;
@@ -56,7 +55,6 @@
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.keyguard.logging.KeyguardLogger;
-import com.android.systemui.res.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.biometrics.AuthController;
import com.android.systemui.biometrics.FaceHelpMessageDeferral;
@@ -72,6 +70,7 @@
import com.android.systemui.keyguard.util.IndicationHelper;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.res.R;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.KeyguardIndicationTextView;
@@ -249,7 +248,6 @@
mFlags = new FakeFeatureFlags();
mFlags.set(KEYGUARD_TALKBACK_FIX, true);
mFlags.set(LOCKSCREEN_WALLPAPER_DREAM_ENABLED, false);
- mFlags.set(FACE_AUTH_REFACTOR, false);
mController = new KeyguardIndicationController(
mContext,
mTestableLooper.getLooper(),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
index dd3ac92..aa53558 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
@@ -479,7 +479,7 @@
createController();
// GIVEN face has already unlocked the device
- when(mKeyguardUpdateMonitor.getUserUnlockedWithFace(anyInt())).thenReturn(true);
+ when(mKeyguardUpdateMonitor.isCurrentUserUnlockedWithFace()).thenReturn(true);
String message = "A message";
mController.setVisible(true);
@@ -586,7 +586,7 @@
createController();
String message = mContext.getString(R.string.keyguard_retry);
when(mStatusBarKeyguardViewManager.isBouncerShowing()).thenReturn(true);
- when(mKeyguardUpdateMonitor.isFaceEnrolled()).thenReturn(true);
+ when(mKeyguardUpdateMonitor.isFaceEnabledAndEnrolled()).thenReturn(true);
when(mKeyguardUpdateMonitor.getIsFaceAuthenticated()).thenReturn(false);
mController.setVisible(true);
@@ -602,7 +602,7 @@
String message = mContext.getString(R.string.keyguard_retry);
when(mStatusBarKeyguardViewManager.isBouncerShowing()).thenReturn(true);
when(mKeyguardUpdateMonitor.getIsFaceAuthenticated()).thenReturn(true);
- when(mKeyguardUpdateMonitor.isFaceEnrolled()).thenReturn(true);
+ when(mKeyguardUpdateMonitor.isFaceEnabledAndEnrolled()).thenReturn(true);
mController.setVisible(true);
mController.getKeyguardCallback().onBiometricError(FACE_ERROR_TIMEOUT,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
index 8fa7cd2..7546dfa 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
@@ -66,8 +66,8 @@
import org.mockito.Mockito
import org.mockito.Mockito.mock
import org.mockito.Mockito.verify
-import org.mockito.MockitoAnnotations
import org.mockito.Mockito.`when` as whenever
+import org.mockito.MockitoAnnotations
@SmallTest
@RunWith(AndroidTestingRunner::class)
@@ -93,88 +93,98 @@
whenever(interactionJankMonitor.end(anyInt())).thenReturn(true)
uiEventLogger = UiEventLoggerFake()
- controller = object : StatusBarStateControllerImpl(
- uiEventLogger,
- interactionJankMonitor,
- mock(),
- { shadeInteractor }
- ) {
- override fun createDarkAnimator(): ObjectAnimator { return mockDarkAnimator }
- }
+ controller =
+ object :
+ StatusBarStateControllerImpl(
+ uiEventLogger,
+ interactionJankMonitor,
+ mock(),
+ { shadeInteractor }
+ ) {
+ override fun createDarkAnimator(): ObjectAnimator {
+ return mockDarkAnimator
+ }
+ }
- val powerInteractor = PowerInteractor(
- FakePowerRepository(),
- FalsingCollectorFake(),
- mock(),
- controller)
+ val powerInteractor =
+ PowerInteractor(FakePowerRepository(), FalsingCollectorFake(), mock(), controller)
val keyguardRepository = FakeKeyguardRepository()
val keyguardTransitionRepository = FakeKeyguardTransitionRepository()
val featureFlags = FakeFeatureFlagsClassic()
val shadeRepository = FakeShadeRepository()
val sceneContainerFlags = FakeSceneContainerFlags()
val configurationRepository = FakeConfigurationRepository()
- val keyguardInteractor = KeyguardInteractor(
- keyguardRepository,
- FakeCommandQueue(),
- powerInteractor,
- featureFlags,
- sceneContainerFlags,
- FakeKeyguardBouncerRepository(),
- configurationRepository,
- shadeRepository,
- utils::sceneInteractor)
- val keyguardTransitionInteractor = KeyguardTransitionInteractor(
- testScope.backgroundScope,
- keyguardTransitionRepository,
- { keyguardInteractor },
- { fromLockscreenTransitionInteractor },
- { fromPrimaryBouncerTransitionInteractor })
- fromLockscreenTransitionInteractor = FromLockscreenTransitionInteractor(
- keyguardTransitionRepository,
- keyguardTransitionInteractor,
- testScope.backgroundScope,
- keyguardInteractor,
- featureFlags,
- shadeRepository,
- powerInteractor,
- {
- InWindowLauncherUnlockAnimationInteractor(
- InWindowLauncherUnlockAnimationRepository(),
- testScope,
- keyguardTransitionInteractor,
- { FakeKeyguardSurfaceBehindRepository() },
- mock(),
- )
- })
- fromPrimaryBouncerTransitionInteractor = FromPrimaryBouncerTransitionInteractor(
- keyguardTransitionRepository,
- keyguardTransitionInteractor,
- testScope.backgroundScope,
- keyguardInteractor,
- featureFlags,
- mock(),
- mock(),
- powerInteractor)
- shadeInteractor = ShadeInteractorImpl(
- testScope.backgroundScope,
- FakeDeviceProvisioningRepository(),
- FakeDisableFlagsRepository(),
- mock(),
- keyguardRepository,
- keyguardTransitionInteractor,
- powerInteractor,
- FakeUserSetupRepository(),
- mock(),
- ShadeInteractorLegacyImpl(
- testScope.backgroundScope,
+ val keyguardInteractor =
+ KeyguardInteractor(
keyguardRepository,
- SharedNotificationContainerInteractor(
- configurationRepository,
- mContext,
- ResourcesSplitShadeStateController()),
+ FakeCommandQueue(),
+ powerInteractor,
+ sceneContainerFlags,
+ FakeKeyguardBouncerRepository(),
+ configurationRepository,
shadeRepository,
+ utils::sceneInteractor
)
- )
+ val keyguardTransitionInteractor =
+ KeyguardTransitionInteractor(
+ testScope.backgroundScope,
+ keyguardTransitionRepository,
+ { keyguardInteractor },
+ { fromLockscreenTransitionInteractor },
+ { fromPrimaryBouncerTransitionInteractor }
+ )
+ fromLockscreenTransitionInteractor =
+ FromLockscreenTransitionInteractor(
+ keyguardTransitionRepository,
+ keyguardTransitionInteractor,
+ testScope.backgroundScope,
+ keyguardInteractor,
+ featureFlags,
+ shadeRepository,
+ powerInteractor,
+ {
+ InWindowLauncherUnlockAnimationInteractor(
+ InWindowLauncherUnlockAnimationRepository(),
+ testScope,
+ keyguardTransitionInteractor,
+ { FakeKeyguardSurfaceBehindRepository() },
+ mock(),
+ )
+ }
+ )
+ fromPrimaryBouncerTransitionInteractor =
+ FromPrimaryBouncerTransitionInteractor(
+ keyguardTransitionRepository,
+ keyguardTransitionInteractor,
+ testScope.backgroundScope,
+ keyguardInteractor,
+ featureFlags,
+ mock(),
+ mock(),
+ powerInteractor
+ )
+ shadeInteractor =
+ ShadeInteractorImpl(
+ testScope.backgroundScope,
+ FakeDeviceProvisioningRepository(),
+ FakeDisableFlagsRepository(),
+ mock(),
+ keyguardRepository,
+ keyguardTransitionInteractor,
+ powerInteractor,
+ FakeUserSetupRepository(),
+ mock(),
+ ShadeInteractorLegacyImpl(
+ testScope.backgroundScope,
+ keyguardRepository,
+ SharedNotificationContainerInteractor(
+ configurationRepository,
+ mContext,
+ ResourcesSplitShadeStateController()
+ ),
+ shadeRepository,
+ )
+ )
}
@Test
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 d1a46fc..057dcb2 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
@@ -62,7 +62,7 @@
private val ongoingCallRepository = OngoingCallRepository()
private val underTest =
- StatusBarModeRepositoryImpl(
+ StatusBarModePerDisplayRepositoryImpl(
testScope.backgroundScope,
DISPLAY_ID,
commandQueue,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModelTest.kt
index 10d4c62..b3fc25c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModelTest.kt
@@ -93,7 +93,6 @@
test = this,
featureFlags =
FakeFeatureFlagsClassicModule {
- setDefault(Flags.FACE_AUTH_REFACTOR)
set(Flags.FULL_SCREEN_USER_SWITCHER, value = false)
},
mocks =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModelTest.kt
index e264fc0..7415645 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModelTest.kt
@@ -105,7 +105,6 @@
test = this,
featureFlags =
FakeFeatureFlagsClassicModule {
- setDefault(Flags.FACE_AUTH_REFACTOR)
set(Flags.FULL_SCREEN_USER_SWITCHER, value = false)
},
mocks =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderWrapperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderWrapperTest.kt
index 1c7fd56..7361f6b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderWrapperTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderWrapperTest.kt
@@ -18,7 +18,6 @@
import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
-import com.android.systemui.Flags
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider.FullScreenIntentDecision
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider.FullScreenIntentDecision.FSI_DEVICE_NOT_INTERACTIVE
@@ -37,7 +36,7 @@
@RunWith(AndroidTestingRunner::class)
class NotificationInterruptStateProviderWrapperTest : VisualInterruptionDecisionProviderTestBase() {
init {
- setFlagsRule.disableFlags(Flags.FLAG_VISUAL_INTERRUPTIONS_REFACTOR)
+ mSetFlagsRule.disableFlags(VisualInterruptionRefactor.FLAG_NAME)
}
override val provider by lazy {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderImplTest.kt
index df6f0d7..d2c046c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderImplTest.kt
@@ -18,7 +18,6 @@
import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
-import com.android.systemui.Flags
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.interruption.VisualInterruptionType.BUBBLE
import com.android.systemui.statusbar.notification.interruption.VisualInterruptionType.PEEK
@@ -30,7 +29,7 @@
@RunWith(AndroidTestingRunner::class)
class VisualInterruptionDecisionProviderImplTest : VisualInterruptionDecisionProviderTestBase() {
init {
- setFlagsRule.enableFlags(Flags.FLAG_VISUAL_INTERRUPTIONS_REFACTOR)
+ mSetFlagsRule.enableFlags(VisualInterruptionRefactor.FLAG_NAME)
}
override val provider by lazy {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestBase.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestBase.kt
index 7babff5..2ac0cb7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestBase.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestBase.kt
@@ -44,7 +44,6 @@
import android.hardware.display.FakeAmbientDisplayConfiguration
import android.os.Looper
import android.os.PowerManager
-import android.platform.test.flag.junit.SetFlagsRule
import android.provider.Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED
import android.provider.Settings.Global.HEADS_UP_OFF
import android.provider.Settings.Global.HEADS_UP_ON
@@ -84,15 +83,10 @@
import junit.framework.Assert.assertTrue
import org.junit.Assert.assertEquals
import org.junit.Before
-import org.junit.Rule
import org.junit.Test
import org.mockito.Mockito.`when` as whenever
abstract class VisualInterruptionDecisionProviderTestBase : SysuiTestCase() {
- @JvmField
- @Rule
- val setFlagsRule = SetFlagsRule(SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT)
-
private val fakeLogBuffer =
LogBuffer(
name = "FakeLog",
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
index e61b4f8..051a4c1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
@@ -135,7 +135,7 @@
MockitoAnnotations.initMocks(this);
when(mKeyguardStateController.isShowing()).thenReturn(true);
when(mUpdateMonitor.isDeviceInteractive()).thenReturn(true);
- when(mKeyguardStateController.isFaceEnrolled()).thenReturn(true);
+ when(mKeyguardStateController.isFaceEnrolledAndEnabled()).thenReturn(true);
when(mKeyguardStateController.isUnlocked()).thenReturn(false);
when(mKeyguardBypassController.onBiometricAuthenticated(any(), anyBoolean()))
.thenReturn(true);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
index 4b1c7e8..4422764 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
@@ -157,6 +157,7 @@
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderImpl;
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderWrapper;
import com.android.systemui.statusbar.notification.interruption.VisualInterruptionDecisionProvider;
+import com.android.systemui.statusbar.notification.interruption.VisualInterruptionRefactor;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
@@ -347,6 +348,8 @@
mFeatureFlags.set(Flags.ZJ_285570694_LOCKSCREEN_TRANSITION_FROM_AOD, true);
when(mDozeParameters.getAlwaysOn()).thenReturn(true);
mSetFlagsRule.disableFlags(com.android.systemui.Flags.FLAG_DEVICE_ENTRY_UDFPS_REFACTOR);
+ // TODO: b/312476335 - Update to check flag and instantiate old or new implementation.
+ mSetFlagsRule.disableFlags(VisualInterruptionRefactor.FLAG_NAME);
IThermalService thermalService = mock(IThermalService.class);
mPowerManager = new PowerManager(mContext, mPowerManagerService, thermalService,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBypassControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBypassControllerTest.kt
index bd0dbee..91cbc32 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBypassControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBypassControllerTest.kt
@@ -86,7 +86,7 @@
featureFlags.set(Flags.FULL_SCREEN_USER_SWITCHER, true)
whenever(packageManager.hasSystemFeature(PackageManager.FEATURE_FACE)).thenReturn(true)
- whenever(keyguardStateController.isFaceEnrolled).thenReturn(true)
+ whenever(keyguardStateController.isFaceEnrolledAndEnabled).thenReturn(true)
}
@After
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java
index 361df1c..62a2bc5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java
@@ -60,7 +60,6 @@
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository;
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.power.domain.interactor.PowerInteractor;
import com.android.systemui.power.domain.interactor.PowerInteractorFactory;
import com.android.systemui.res.R;
import com.android.systemui.scene.SceneTestUtils;
@@ -166,7 +165,6 @@
mKeyguardRepository,
mCommandQueue,
PowerInteractorFactory.create().getPowerInteractor(),
- mFeatureFlags,
mSceneTestUtils.getSceneContainerFlags(),
new FakeKeyguardBouncerRepository(),
new FakeConfigurationRepository(),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightsOutNotifControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LegacyLightsOutNotifControllerTest.java
similarity index 97%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightsOutNotifControllerTest.java
rename to packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LegacyLightsOutNotifControllerTest.java
index 287ebba..bde2243 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightsOutNotifControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LegacyLightsOutNotifControllerTest.java
@@ -54,7 +54,7 @@
@SmallTest
@RunWith(AndroidTestingRunner.class)
@RunWithLooper
-public class LightsOutNotifControllerTest extends SysuiTestCase {
+public class LegacyLightsOutNotifControllerTest extends SysuiTestCase {
private static final int LIGHTS_ON = 0;
private static final int LIGHTS_OUT = APPEARANCE_LOW_PROFILE_BARS;
@@ -68,7 +68,7 @@
@Captor private ArgumentCaptor<CommandQueue.Callbacks> mCallbacksCaptor;
private View mLightsOutView;
- private LightsOutNotifController mLightsOutNotifController;
+ private LegacyLightsOutNotifController mLightsOutNotifController;
private int mDisplayId;
private Observer<Boolean> mHaActiveNotifsObserver;
private CommandQueue.Callbacks mCallbacks;
@@ -83,7 +83,7 @@
when(mNotifLiveDataStore.getHasActiveNotifs()).thenReturn(mHasActiveNotifs);
when(mHasActiveNotifs.getValue()).thenReturn(false);
- mLightsOutNotifController = new LightsOutNotifController(
+ mLightsOutNotifController = new LegacyLightsOutNotifController(
mLightsOutView,
mWindowManager,
mNotifLiveDataStore,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightBarControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightBarControllerTest.java
index c45ecf3..f6419a9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightBarControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightBarControllerTest.java
@@ -121,7 +121,7 @@
new AppearanceRegion(APPEARANCE_LIGHT_STATUS_BARS, secondBounds)
);
- mStatusBarModeRepository.getStatusBarAppearance().setValue(
+ mStatusBarModeRepository.getDefaultDisplay().getStatusBarAppearance().setValue(
new StatusBarAppearance(
StatusBarMode.TRANSPARENT,
STATUS_BAR_BOUNDS,
@@ -142,7 +142,7 @@
new AppearanceRegion(0 /* appearance */, secondBounds)
);
- mStatusBarModeRepository.getStatusBarAppearance().setValue(
+ mStatusBarModeRepository.getDefaultDisplay().getStatusBarAppearance().setValue(
new StatusBarAppearance(
StatusBarMode.TRANSPARENT,
STATUS_BAR_BOUNDS,
@@ -165,7 +165,7 @@
new AppearanceRegion(APPEARANCE_LIGHT_STATUS_BARS, secondBounds)
);
- mStatusBarModeRepository.getStatusBarAppearance().setValue(
+ mStatusBarModeRepository.getDefaultDisplay().getStatusBarAppearance().setValue(
new StatusBarAppearance(
StatusBarMode.TRANSPARENT,
STATUS_BAR_BOUNDS,
@@ -190,7 +190,7 @@
new AppearanceRegion(APPEARANCE_LIGHT_STATUS_BARS, thirdBounds)
);
- mStatusBarModeRepository.getStatusBarAppearance().setValue(
+ mStatusBarModeRepository.getDefaultDisplay().getStatusBarAppearance().setValue(
new StatusBarAppearance(
StatusBarMode.TRANSPARENT,
STATUS_BAR_BOUNDS,
@@ -214,7 +214,7 @@
new AppearanceRegion(0 /* appearance */, secondBounds)
);
- mStatusBarModeRepository.getStatusBarAppearance().setValue(
+ mStatusBarModeRepository.getDefaultDisplay().getStatusBarAppearance().setValue(
new StatusBarAppearance(
StatusBarMode.TRANSPARENT,
STATUS_BAR_BOUNDS,
@@ -231,7 +231,7 @@
new AppearanceRegion(APPEARANCE_LIGHT_STATUS_BARS, new Rect(0, 0, 1, 1))
);
- mStatusBarModeRepository.getStatusBarAppearance().setValue(
+ mStatusBarModeRepository.getDefaultDisplay().getStatusBarAppearance().setValue(
new StatusBarAppearance(
StatusBarMode.TRANSPARENT,
STATUS_BAR_BOUNDS,
@@ -249,7 +249,7 @@
new AppearanceRegion(0, new Rect(0, 0, 1, 1))
);
- mStatusBarModeRepository.getStatusBarAppearance().setValue(
+ mStatusBarModeRepository.getDefaultDisplay().getStatusBarAppearance().setValue(
new StatusBarAppearance(
StatusBarMode.TRANSPARENT,
STATUS_BAR_BOUNDS,
@@ -266,7 +266,7 @@
new AppearanceRegion(APPEARANCE_LIGHT_STATUS_BARS, new Rect(0, 0, 1, 1))
);
- mStatusBarModeRepository.getStatusBarAppearance().setValue(
+ mStatusBarModeRepository.getDefaultDisplay().getStatusBarAppearance().setValue(
new StatusBarAppearance(
StatusBarMode.TRANSPARENT,
STATUS_BAR_BOUNDS,
@@ -276,7 +276,7 @@
reset(mStatusBarIconController);
// WHEN the same appearance regions but different status bar mode is sent
- mStatusBarModeRepository.getStatusBarAppearance().setValue(
+ mStatusBarModeRepository.getDefaultDisplay().getStatusBarAppearance().setValue(
new StatusBarAppearance(
StatusBarMode.LIGHTS_OUT_TRANSPARENT,
STATUS_BAR_BOUNDS,
@@ -298,7 +298,7 @@
/* start= */ new Rect(0, 0, 10, 10),
/* end= */ new Rect(0, 0, 20, 20));
- mStatusBarModeRepository.getStatusBarAppearance().setValue(
+ mStatusBarModeRepository.getDefaultDisplay().getStatusBarAppearance().setValue(
new StatusBarAppearance(
StatusBarMode.TRANSPARENT,
startingBounds,
@@ -311,7 +311,7 @@
BoundsPair newBounds = new BoundsPair(
/* start= */ new Rect(0, 0, 30, 30),
/* end= */ new Rect(0, 0, 40, 40));
- mStatusBarModeRepository.getStatusBarAppearance().setValue(
+ mStatusBarModeRepository.getDefaultDisplay().getStatusBarAppearance().setValue(
new StatusBarAppearance(
StatusBarMode.TRANSPARENT,
newBounds,
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
new file mode 100644
index 0000000..5a0e13d
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/domain/interactor/LightsOutInteractorTest.kt
@@ -0,0 +1,62 @@
+/*
+ * 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.systemui.statusbar.phone.domain.interactor
+
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.statusbar.data.model.StatusBarMode
+import com.android.systemui.statusbar.data.repository.FakeStatusBarModeRepository
+import com.android.systemui.statusbar.data.repository.FakeStatusBarModeRepository.Companion.DISPLAY_ID
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+
+@SmallTest
+class LightsOutInteractorTest : SysuiTestCase() {
+
+ private val statusBarModeRepository = FakeStatusBarModeRepository()
+ private val interactor: LightsOutInteractor = LightsOutInteractor(statusBarModeRepository)
+
+ @Test
+ fun isLowProfile_lightsOutStatusBarMode_false() = runTest {
+ statusBarModeRepository.defaultDisplay.statusBarMode.value = StatusBarMode.LIGHTS_OUT
+
+ val actual by collectLastValue(interactor.isLowProfile(DISPLAY_ID))
+
+ assertThat(actual).isTrue()
+ }
+
+ @Test
+ fun isLowProfile_lightsOutTransparentStatusBarMode_true() = runTest {
+ statusBarModeRepository.defaultDisplay.statusBarMode.value =
+ StatusBarMode.LIGHTS_OUT_TRANSPARENT
+
+ val actual by collectLastValue(interactor.isLowProfile(DISPLAY_ID))
+
+ assertThat(actual).isTrue()
+ }
+
+ @Test
+ fun isLowProfile_transparentStatusBarMode_false() = runTest {
+ statusBarModeRepository.defaultDisplay.statusBarMode.value = StatusBarMode.TRANSPARENT
+
+ val actual by collectLastValue(interactor.isLowProfile(DISPLAY_ID))
+
+ assertThat(actual).isFalse()
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
index 0b87fe8..17c2938 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
@@ -46,7 +46,6 @@
import com.android.systemui.common.ui.ConfigurationState;
import com.android.systemui.demomode.DemoModeController;
import com.android.systemui.dump.DumpManager;
-import com.android.systemui.flags.FeatureFlagsClassic;
import com.android.systemui.log.LogBuffer;
import com.android.systemui.log.LogcatEchoTracker;
import com.android.systemui.plugins.DarkIconDispatcher;
@@ -695,7 +694,6 @@
mLocationPublisher,
mMockNotificationAreaController,
mShadeExpansionStateManager,
- mock(FeatureFlagsClassic.class),
mStatusBarIconController,
mIconManagerFactory,
mCollapsedStatusBarViewModel,
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 49de512..7b73528c 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
@@ -549,7 +549,7 @@
@Test
fun fullscreenIsTrue_chipStillClickable() {
notifCollectionListener.onEntryUpdated(createOngoingCallNotifEntry())
- statusBarModeRepository.isInFullscreenMode.value = true
+ statusBarModeRepository.defaultDisplay.isInFullscreenMode.value = true
testScope.runCurrent()
assertThat(chipView.hasOnClickListeners()).isTrue()
@@ -559,7 +559,7 @@
@Test
fun callStartedInImmersiveMode_swipeGestureCallbackAdded() {
- statusBarModeRepository.isInFullscreenMode.value = true
+ statusBarModeRepository.defaultDisplay.isInFullscreenMode.value = true
testScope.runCurrent()
notifCollectionListener.onEntryUpdated(createOngoingCallNotifEntry())
@@ -570,7 +570,7 @@
@Test
fun callStartedNotInImmersiveMode_swipeGestureCallbackNotAdded() {
- statusBarModeRepository.isInFullscreenMode.value = false
+ statusBarModeRepository.defaultDisplay.isInFullscreenMode.value = false
testScope.runCurrent()
notifCollectionListener.onEntryUpdated(createOngoingCallNotifEntry())
@@ -583,7 +583,7 @@
fun transitionToImmersiveMode_swipeGestureCallbackAdded() {
notifCollectionListener.onEntryUpdated(createOngoingCallNotifEntry())
- statusBarModeRepository.isInFullscreenMode.value = true
+ statusBarModeRepository.defaultDisplay.isInFullscreenMode.value = true
testScope.runCurrent()
verify(mockSwipeStatusBarAwayGestureHandler)
@@ -592,11 +592,11 @@
@Test
fun transitionOutOfImmersiveMode_swipeGestureCallbackRemoved() {
- statusBarModeRepository.isInFullscreenMode.value = true
+ statusBarModeRepository.defaultDisplay.isInFullscreenMode.value = true
notifCollectionListener.onEntryUpdated(createOngoingCallNotifEntry())
reset(mockSwipeStatusBarAwayGestureHandler)
- statusBarModeRepository.isInFullscreenMode.value = false
+ statusBarModeRepository.defaultDisplay.isInFullscreenMode.value = false
testScope.runCurrent()
verify(mockSwipeStatusBarAwayGestureHandler)
@@ -605,7 +605,7 @@
@Test
fun callEndedWhileInImmersiveMode_swipeGestureCallbackRemoved() {
- statusBarModeRepository.isInFullscreenMode.value = true
+ statusBarModeRepository.defaultDisplay.isInFullscreenMode.value = true
testScope.runCurrent()
val ongoingCallNotifEntry = createOngoingCallNotifEntry()
notifCollectionListener.onEntryAdded(ongoingCallNotifEntry)
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 688f739..09dc1e5 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
@@ -17,49 +17,77 @@
package com.android.systemui.statusbar.pipeline.shared.ui.viewmodel
import androidx.test.filters.SmallTest
+import com.android.systemui.CoroutineTestScopeModule
+import com.android.systemui.Flags
+import com.android.systemui.SysUITestComponent
+import com.android.systemui.SysUITestModule
import com.android.systemui.SysuiTestCase
-import com.android.systemui.coroutines.collectValues
+import com.android.systemui.collectLastValue
+import com.android.systemui.collectValues
+import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
-import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractorFactory
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionStep
+import com.android.systemui.runTest
+import com.android.systemui.statusbar.data.model.StatusBarMode
+import com.android.systemui.statusbar.data.repository.FakeStatusBarModeRepository
+import com.android.systemui.statusbar.data.repository.FakeStatusBarModeRepository.Companion.DISPLAY_ID
+import com.android.systemui.statusbar.notification.data.model.activeNotificationModel
+import com.android.systemui.statusbar.notification.data.repository.ActiveNotificationListRepository
+import com.android.systemui.statusbar.notification.data.repository.ActiveNotificationsStore
+import com.android.systemui.statusbar.notification.shared.ActiveNotificationModel
import com.google.common.truth.Truth.assertThat
+import dagger.BindsInstance
+import dagger.Component
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.UnconfinedTestDispatcher
-import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
-@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
class CollapsedStatusBarViewModelImplTest : SysuiTestCase() {
- private lateinit var underTest: CollapsedStatusBarViewModel
+ @SysUISingleton
+ @Component(
+ modules =
+ [
+ SysUITestModule::class,
+ ]
+ )
+ interface TestComponent : SysUITestComponent<CollapsedStatusBarViewModelImpl> {
+ val statusBarModeRepository: FakeStatusBarModeRepository
+ val activeNotificationListRepository: ActiveNotificationListRepository
+ val keyguardTransitionRepository: FakeKeyguardTransitionRepository
- private lateinit var keyguardTransitionRepository: FakeKeyguardTransitionRepository
- private lateinit var testScope: TestScope
+ @Component.Factory
+ interface Factory {
+ fun create(
+ @BindsInstance test: SysuiTestCase,
+ testScope: CoroutineTestScopeModule,
+ ): TestComponent
+ }
+ }
+
+ @OptIn(ExperimentalCoroutinesApi::class)
+ private val testComponent: TestComponent =
+ DaggerCollapsedStatusBarViewModelImplTest_TestComponent.factory()
+ .create(
+ test = this,
+ testScope = CoroutineTestScopeModule(TestScope(UnconfinedTestDispatcher())),
+ )
@Before
fun setUp() {
- testScope = TestScope(UnconfinedTestDispatcher())
-
- keyguardTransitionRepository = FakeKeyguardTransitionRepository()
- val interactor =
- KeyguardTransitionInteractorFactory.create(
- scope = TestScope().backgroundScope,
- repository = keyguardTransitionRepository,
- )
- .keyguardTransitionInteractor
- underTest = CollapsedStatusBarViewModelImpl(interactor, testScope.backgroundScope)
+ mSetFlagsRule.enableFlags(Flags.FLAG_NOTIFICATIONS_LIVE_DATA_STORE_REFACTOR)
}
@Test
fun isTransitioningFromLockscreenToOccluded_started_isTrue() =
- testScope.runTest {
- val job = underTest.isTransitioningFromLockscreenToOccluded.launchIn(this)
+ testComponent.runTest {
+ val job = underTest.isTransitioningFromLockscreenToOccluded.launchIn(testScope)
keyguardTransitionRepository.sendTransitionStep(
TransitionStep(
@@ -77,8 +105,8 @@
@Test
fun isTransitioningFromLockscreenToOccluded_running_isTrue() =
- testScope.runTest {
- val job = underTest.isTransitioningFromLockscreenToOccluded.launchIn(this)
+ testComponent.runTest {
+ val job = underTest.isTransitioningFromLockscreenToOccluded.launchIn(testScope)
keyguardTransitionRepository.sendTransitionStep(
TransitionStep(
@@ -96,13 +124,13 @@
@Test
fun isTransitioningFromLockscreenToOccluded_finished_isFalse() =
- testScope.runTest {
- val job = underTest.isTransitioningFromLockscreenToOccluded.launchIn(this)
+ testComponent.runTest {
+ val job = underTest.isTransitioningFromLockscreenToOccluded.launchIn(testScope)
keyguardTransitionRepository.sendTransitionSteps(
from = KeyguardState.LOCKSCREEN,
to = KeyguardState.OCCLUDED,
- this.testScheduler,
+ testScope.testScheduler,
)
assertThat(underTest.isTransitioningFromLockscreenToOccluded.value).isFalse()
@@ -112,8 +140,8 @@
@Test
fun isTransitioningFromLockscreenToOccluded_canceled_isFalse() =
- testScope.runTest {
- val job = underTest.isTransitioningFromLockscreenToOccluded.launchIn(this)
+ testComponent.runTest {
+ val job = underTest.isTransitioningFromLockscreenToOccluded.launchIn(testScope)
keyguardTransitionRepository.sendTransitionStep(
TransitionStep(
@@ -131,8 +159,8 @@
@Test
fun isTransitioningFromLockscreenToOccluded_irrelevantTransition_isFalse() =
- testScope.runTest {
- val job = underTest.isTransitioningFromLockscreenToOccluded.launchIn(this)
+ testComponent.runTest {
+ val job = underTest.isTransitioningFromLockscreenToOccluded.launchIn(testScope)
keyguardTransitionRepository.sendTransitionStep(
TransitionStep(
@@ -150,8 +178,8 @@
@Test
fun isTransitioningFromLockscreenToOccluded_followsRepoUpdates() =
- testScope.runTest {
- val job = underTest.isTransitioningFromLockscreenToOccluded.launchIn(this)
+ testComponent.runTest {
+ val job = underTest.isTransitioningFromLockscreenToOccluded.launchIn(testScope)
keyguardTransitionRepository.sendTransitionStep(
TransitionStep(
@@ -182,7 +210,7 @@
@Test
fun transitionFromLockscreenToDreamStartedEvent_started_emitted() =
- testScope.runTest {
+ testComponent.runTest {
val emissions by collectValues(underTest.transitionFromLockscreenToDreamStartedEvent)
keyguardTransitionRepository.sendTransitionStep(
@@ -199,7 +227,7 @@
@Test
fun transitionFromLockscreenToDreamStartedEvent_startedMultiple_emittedMultiple() =
- testScope.runTest {
+ testComponent.runTest {
val emissions by collectValues(underTest.transitionFromLockscreenToDreamStartedEvent)
keyguardTransitionRepository.sendTransitionStep(
@@ -234,7 +262,7 @@
@Test
fun transitionFromLockscreenToDreamStartedEvent_startedThenRunning_emittedOnlyOne() =
- testScope.runTest {
+ testComponent.runTest {
val emissions by collectValues(underTest.transitionFromLockscreenToDreamStartedEvent)
keyguardTransitionRepository.sendTransitionStep(
@@ -283,7 +311,7 @@
@Test
fun transitionFromLockscreenToDreamStartedEvent_irrelevantTransition_notEmitted() =
- testScope.runTest {
+ testComponent.runTest {
val emissions by collectValues(underTest.transitionFromLockscreenToDreamStartedEvent)
keyguardTransitionRepository.sendTransitionStep(
@@ -300,7 +328,7 @@
@Test
fun transitionFromLockscreenToDreamStartedEvent_irrelevantTransitionState_notEmitted() =
- testScope.runTest {
+ testComponent.runTest {
val emissions by collectValues(underTest.transitionFromLockscreenToDreamStartedEvent)
keyguardTransitionRepository.sendTransitionStep(
@@ -317,4 +345,65 @@
assertThat(emissions).isEmpty()
}
+
+ @Test
+ fun areNotificationsLightsOut_lowProfileWithNotifications_true() =
+ testComponent.runTest {
+ statusBarModeRepository.defaultDisplay.statusBarMode.value =
+ StatusBarMode.LIGHTS_OUT_TRANSPARENT
+ activeNotificationListRepository.activeNotifications.value =
+ activeNotificationsStore(testNotifications)
+
+ val actual by collectLastValue(underTest.areNotificationsLightsOut(DISPLAY_ID))
+
+ assertThat(actual).isTrue()
+ }
+
+ @Test
+ fun areNotificationsLightsOut_lowProfileWithoutNotifications_false() =
+ testComponent.runTest {
+ statusBarModeRepository.defaultDisplay.statusBarMode.value =
+ StatusBarMode.LIGHTS_OUT_TRANSPARENT
+ activeNotificationListRepository.activeNotifications.value =
+ activeNotificationsStore(emptyList())
+
+ val actual by collectLastValue(underTest.areNotificationsLightsOut(DISPLAY_ID))
+
+ assertThat(actual).isFalse()
+ }
+
+ @Test
+ fun areNotificationsLightsOut_defaultStatusBarModeWithoutNotifications_false() =
+ testComponent.runTest {
+ statusBarModeRepository.defaultDisplay.statusBarMode.value = StatusBarMode.TRANSPARENT
+ activeNotificationListRepository.activeNotifications.value =
+ activeNotificationsStore(emptyList())
+
+ val actual by collectLastValue(underTest.areNotificationsLightsOut(DISPLAY_ID))
+
+ assertThat(actual).isFalse()
+ }
+
+ @Test
+ fun areNotificationsLightsOut_defaultStatusBarModeWithNotifications_false() =
+ testComponent.runTest {
+ statusBarModeRepository.defaultDisplay.statusBarMode.value = StatusBarMode.TRANSPARENT
+ activeNotificationListRepository.activeNotifications.value =
+ activeNotificationsStore(testNotifications)
+
+ val actual by collectLastValue(underTest.areNotificationsLightsOut(DISPLAY_ID))
+
+ assertThat(actual).isFalse()
+ }
+
+ private fun activeNotificationsStore(notifications: List<ActiveNotificationModel>) =
+ ActiveNotificationsStore.Builder()
+ .apply { notifications.forEach(::addIndividualNotif) }
+ .build()
+
+ private val testNotifications =
+ listOf(
+ activeNotificationModel(key = "notif1"),
+ activeNotificationModel(key = "notif2"),
+ )
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeCollapsedStatusBarViewModel.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeCollapsedStatusBarViewModel.kt
index 88587b2..bc50f79 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeCollapsedStatusBarViewModel.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeCollapsedStatusBarViewModel.kt
@@ -16,11 +16,20 @@
package com.android.systemui.statusbar.pipeline.shared.ui.viewmodel
+import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
class FakeCollapsedStatusBarViewModel : CollapsedStatusBarViewModel {
+ private val areNotificationLightsOut = MutableStateFlow(false)
+
override val isTransitioningFromLockscreenToOccluded = MutableStateFlow(false)
override val transitionFromLockscreenToDreamStartedEvent = MutableSharedFlow<Unit>()
+
+ override fun areNotificationsLightsOut(displayId: Int): Flow<Boolean> = areNotificationLightsOut
+
+ fun setNotificationLightsOut(lightsOut: Boolean) {
+ areNotificationLightsOut.value = lightsOut
+ }
}
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
new file mode 100644
index 0000000..ce47170
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DevicePostureControllerImplTest.kt
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2021 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.policy
+
+import android.hardware.devicestate.DeviceStateManager
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import android.testing.TestableResources
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_CLOSED
+import com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_FLIPPED
+import com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_HALF_OPENED
+import com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_OPENED
+import com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_UNKNOWN
+import com.android.systemui.statusbar.policy.DevicePostureController.SUPPORTED_POSTURES_SIZE
+import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.mockito.eq
+import com.android.systemui.util.time.FakeSystemClock
+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.Captor
+import org.mockito.Mock
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+class DevicePostureControllerImplTest : SysuiTestCase() {
+ private val useBaseStateDeviceState = SUPPORTED_POSTURES_SIZE
+ private val deviceStateToPostureMapping =
+ arrayOf(
+ "$DEVICE_POSTURE_UNKNOWN:$DEVICE_POSTURE_UNKNOWN",
+ "$DEVICE_POSTURE_CLOSED:$DEVICE_POSTURE_CLOSED",
+ "$DEVICE_POSTURE_HALF_OPENED:$DEVICE_POSTURE_HALF_OPENED",
+ "$DEVICE_POSTURE_OPENED:$DEVICE_POSTURE_OPENED",
+ "$DEVICE_POSTURE_FLIPPED:$DEVICE_POSTURE_FLIPPED",
+ "$useBaseStateDeviceState:1000"
+ )
+ @Mock private lateinit var deviceStateManager: DeviceStateManager
+ @Captor
+ private lateinit var deviceStateCallback: ArgumentCaptor<DeviceStateManager.DeviceStateCallback>
+
+ private lateinit var mainExecutor: FakeExecutor
+ private lateinit var testableResources: TestableResources
+ private lateinit var underTest: DevicePostureControllerImpl
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ mainExecutor = FakeExecutor(FakeSystemClock())
+ testableResources = context.getOrCreateTestableResources()
+ testableResources.addOverride(
+ com.android.internal.R.array.config_device_state_postures,
+ deviceStateToPostureMapping
+ )
+ underTest =
+ DevicePostureControllerImpl(
+ context,
+ deviceStateManager,
+ mainExecutor,
+ )
+ verifyRegistersForDeviceStateCallback()
+ }
+
+ @Test
+ fun testPostureChanged_updates() {
+ var posture = -1
+ underTest.addCallback { posture = it }
+
+ deviceStateCallback.value.onStateChanged(DEVICE_POSTURE_UNKNOWN)
+ assertThat(posture).isEqualTo(DEVICE_POSTURE_UNKNOWN)
+
+ deviceStateCallback.value.onStateChanged(DEVICE_POSTURE_CLOSED)
+ assertThat(posture).isEqualTo(DEVICE_POSTURE_CLOSED)
+
+ deviceStateCallback.value.onStateChanged(DEVICE_POSTURE_HALF_OPENED)
+ assertThat(posture).isEqualTo(DEVICE_POSTURE_HALF_OPENED)
+
+ deviceStateCallback.value.onStateChanged(DEVICE_POSTURE_OPENED)
+ assertThat(posture).isEqualTo(DEVICE_POSTURE_OPENED)
+
+ deviceStateCallback.value.onStateChanged(DEVICE_POSTURE_FLIPPED)
+ assertThat(posture).isEqualTo(DEVICE_POSTURE_FLIPPED)
+ }
+
+ @Test
+ fun testPostureChanged_useBaseUpdate() {
+ var posture = -1
+ underTest.addCallback { posture = it }
+
+ deviceStateCallback.value.onStateChanged(DEVICE_POSTURE_HALF_OPENED)
+ assertThat(posture).isEqualTo(DEVICE_POSTURE_HALF_OPENED)
+
+ // base state change doesn't change the posture
+ deviceStateCallback.value.onBaseStateChanged(DEVICE_POSTURE_CLOSED)
+ assertThat(posture).isEqualTo(DEVICE_POSTURE_HALF_OPENED)
+
+ // WHEN the display state maps to using the base state, then posture updates
+ deviceStateCallback.value.onStateChanged(useBaseStateDeviceState)
+ assertThat(posture).isEqualTo(DEVICE_POSTURE_CLOSED)
+ }
+
+ @Test
+ fun baseStateChanges_doesNotUpdatePosture() {
+ var numPostureChanges = 0
+ underTest.addCallback { numPostureChanges++ }
+
+ deviceStateCallback.value.onStateChanged(DEVICE_POSTURE_HALF_OPENED)
+ assertThat(numPostureChanges).isEqualTo(1)
+
+ // base state changes doesn't send another posture update since the device state isn't
+ // useBaseStateDeviceState
+ deviceStateCallback.value.onBaseStateChanged(DEVICE_POSTURE_CLOSED)
+ deviceStateCallback.value.onBaseStateChanged(DEVICE_POSTURE_HALF_OPENED)
+ deviceStateCallback.value.onBaseStateChanged(DEVICE_POSTURE_FLIPPED)
+ deviceStateCallback.value.onBaseStateChanged(DEVICE_POSTURE_OPENED)
+ deviceStateCallback.value.onBaseStateChanged(DEVICE_POSTURE_UNKNOWN)
+ assertThat(numPostureChanges).isEqualTo(1)
+ }
+
+ private fun verifyRegistersForDeviceStateCallback() {
+ verify(deviceStateManager).registerCallback(eq(mainExecutor), deviceStateCallback.capture())
+ }
+}
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 5c960b6..01dad38 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
@@ -100,16 +100,16 @@
public void testFaceAuthEnrolleddChanged_calledWhenFaceEnrollmentStateChanges() {
KeyguardStateController.Callback callback = mock(KeyguardStateController.Callback.class);
- when(mKeyguardUpdateMonitor.isFaceEnrolled(anyInt())).thenReturn(false);
+ when(mKeyguardUpdateMonitor.isFaceEnabledAndEnrolled()).thenReturn(false);
verify(mKeyguardUpdateMonitor).registerCallback(mUpdateCallbackCaptor.capture());
mKeyguardStateController.addCallback(callback);
- assertThat(mKeyguardStateController.isFaceEnrolled()).isFalse();
+ assertThat(mKeyguardStateController.isFaceEnrolledAndEnabled()).isFalse();
- when(mKeyguardUpdateMonitor.isFaceEnrolled(anyInt())).thenReturn(true);
+ when(mKeyguardUpdateMonitor.isFaceEnabledAndEnrolled()).thenReturn(true);
mUpdateCallbackCaptor.getValue().onBiometricEnrollmentStateChanged(
BiometricSourceType.FACE);
- assertThat(mKeyguardStateController.isFaceEnrolled()).isTrue();
+ assertThat(mKeyguardStateController.isFaceEnrolledAndEnabled()).isTrue();
verify(callback).onFaceEnrolledChanged();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/ui/viewmodel/KeyguardStatusBarViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/ui/viewmodel/KeyguardStatusBarViewModelTest.kt
index 96db09e..59bf9f3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/ui/viewmodel/KeyguardStatusBarViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/ui/viewmodel/KeyguardStatusBarViewModelTest.kt
@@ -21,7 +21,6 @@
import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository
import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository
import com.android.systemui.coroutines.collectLastValue
-import com.android.systemui.flags.FakeFeatureFlagsClassic
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.keyguard.shared.model.StatusBarState
@@ -55,7 +54,6 @@
keyguardRepository,
mock<CommandQueue>(),
PowerInteractorFactory.create().powerInteractor,
- FakeFeatureFlagsClassic(),
sceneTestUtils.sceneContainerFlags,
FakeKeyguardBouncerRepository(),
FakeConfigurationRepository(),
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 7f990a4..f924134 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldAodAnimationControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldAodAnimationControllerTest.kt
@@ -26,7 +26,6 @@
import com.android.internal.util.LatencyTracker
import com.android.systemui.SysuiTestCase
import com.android.systemui.flags.FakeFeatureFlags
-import com.android.systemui.flags.Flags.FACE_AUTH_REFACTOR
import com.android.systemui.keyguard.WakefulnessLifecycle
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory
@@ -106,8 +105,7 @@
onActionStarted.run()
}
- val featureFlags = FakeFeatureFlags().apply { set(FACE_AUTH_REFACTOR, true) }
- val withDeps = KeyguardInteractorFactory.create(featureFlags = featureFlags)
+ val withDeps = KeyguardInteractorFactory.create(featureFlags = FakeFeatureFlags())
val keyguardInteractor = withDeps.keyguardInteractor
keyguardRepository = withDeps.repository
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 0d78ae9..abfff34 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
@@ -23,8 +23,6 @@
import android.provider.Settings
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
-import com.android.systemui.flags.FakeFeatureFlags
-import com.android.systemui.flags.Flags.FACE_AUTH_REFACTOR
import com.android.systemui.settings.FakeUserTracker
import com.android.systemui.user.data.model.SelectedUserModel
import com.android.systemui.user.data.model.SelectionStatus
@@ -322,8 +320,6 @@
}
private fun create(scope: CoroutineScope = TestCoroutineScope()): UserRepositoryImpl {
- val featureFlags = FakeFeatureFlags()
- featureFlags.set(FACE_AUTH_REFACTOR, true)
return UserRepositoryImpl(
appContext = context,
manager = manager,
@@ -332,7 +328,6 @@
backgroundDispatcher = IMMEDIATE,
globalSettings = globalSettings,
tracker = tracker,
- featureFlags = featureFlags,
)
}
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 017eefe..bf851eb 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
@@ -121,8 +121,6 @@
)
utils.featureFlags.set(Flags.FULL_SCREEN_USER_SWITCHER, false)
- utils.featureFlags.set(Flags.FACE_AUTH_REFACTOR, true)
-
spyContext = spy(context)
keyguardReply = KeyguardInteractorFactory.create(featureFlags = utils.featureFlags)
keyguardRepository = keyguardReply.repository
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 7041eab..d1870b1 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
@@ -233,11 +233,7 @@
}
private fun viewModel(): StatusBarUserChipViewModel {
- val featureFlags =
- FakeFeatureFlags().apply {
- set(Flags.FULL_SCREEN_USER_SWITCHER, false)
- set(Flags.FACE_AUTH_REFACTOR, true)
- }
+ val featureFlags = FakeFeatureFlags().apply { set(Flags.FULL_SCREEN_USER_SWITCHER, false) }
runBlocking {
userRepository.setUserInfos(listOf(USER_0))
userRepository.setSelectedUserInfo(USER_0)
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 686f492..b7b24f6 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
@@ -147,11 +147,7 @@
resetOrExitSessionReceiver = resetOrExitSessionReceiver,
)
- val featureFlags =
- FakeFeatureFlags().apply {
- set(Flags.FULL_SCREEN_USER_SWITCHER, false)
- set(Flags.FACE_AUTH_REFACTOR, true)
- }
+ val featureFlags = FakeFeatureFlags().apply { set(Flags.FULL_SCREEN_USER_SWITCHER, false) }
val reply = KeyguardInteractorFactory.create(featureFlags = featureFlags)
keyguardRepository = reply.repository
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
index df7609c..ca167ad 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
@@ -146,6 +146,7 @@
import com.android.systemui.statusbar.notification.interruption.KeyguardNotificationVisibilityProvider;
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptLogger;
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderWrapper;
+import com.android.systemui.statusbar.notification.interruption.VisualInterruptionRefactor;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.NotificationTestHelper;
import com.android.systemui.statusbar.notification.stack.domain.interactor.SharedNotificationContainerInteractor;
@@ -366,6 +367,9 @@
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
+ // TODO: b/312476335 - Update to check flag and instantiate old or new implementation.
+ mSetFlagsRule.disableFlags(VisualInterruptionRefactor.FLAG_NAME);
+
if (Transitions.ENABLE_SHELL_TRANSITIONS) {
doReturn(true).when(mTransitions).isRegistered();
}
@@ -411,7 +415,6 @@
keyguardRepository,
new FakeCommandQueue(),
powerInteractor,
- featureFlags,
sceneContainerFlags,
new FakeKeyguardBouncerRepository(),
configurationRepository,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeBiometricSettingsRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeBiometricSettingsRepository.kt
index df31a12..1381464 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeBiometricSettingsRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeBiometricSettingsRepository.kt
@@ -47,7 +47,7 @@
get() = _isFaceAuthCurrentlyAllowed
private val _isFaceAuthSupportedInCurrentPosture = MutableStateFlow(false)
- override val isFaceAuthSupportedInCurrentPosture: Flow<Boolean>
+ override val isFaceAuthSupportedInCurrentPosture: StateFlow<Boolean>
get() = _isFaceAuthSupportedInCurrentPosture
override val isCurrentUserInLockdown: Flow<Boolean>
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractorFactory.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractorFactory.kt
index 6c2ce71..3d8ae1e 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractorFactory.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractorFactory.kt
@@ -81,6 +81,7 @@
trustRepository,
testScope.backgroundScope,
mock(SelectedUserInteractor::class.java),
+ mock(KeyguardFaceAuthInteractor::class.java),
)
val alternateBouncerInteractor =
AlternateBouncerInteractor(
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorFactory.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorFactory.kt
index d2ff9bc5..c575bb3 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorFactory.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorFactory.kt
@@ -20,7 +20,6 @@
import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository
import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository
import com.android.systemui.flags.FakeFeatureFlags
-import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.data.repository.FakeCommandQueue
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.power.domain.interactor.PowerInteractor
@@ -40,7 +39,7 @@
@JvmOverloads
@JvmStatic
fun create(
- featureFlags: FakeFeatureFlags = createFakeFeatureFlags(),
+ featureFlags: FakeFeatureFlags = FakeFeatureFlags(),
sceneContainerFlags: SceneContainerFlags = FakeSceneContainerFlags(),
repository: FakeKeyguardRepository = FakeKeyguardRepository(),
commandQueue: FakeCommandQueue = FakeCommandQueue(),
@@ -62,7 +61,6 @@
KeyguardInteractor(
repository = repository,
commandQueue = commandQueue,
- featureFlags = featureFlags,
sceneContainerFlags = sceneContainerFlags,
bouncerRepository = bouncerRepository,
configurationRepository = configurationRepository,
@@ -73,11 +71,6 @@
)
}
- /** Provide defaults, otherwise tests will throw an error */
- private fun createFakeFeatureFlags(): FakeFeatureFlags {
- return FakeFeatureFlags().apply { set(Flags.FACE_AUTH_REFACTOR, false) }
- }
-
data class WithDependencies(
val repository: FakeKeyguardRepository,
val commandQueue: FakeCommandQueue,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorKosmos.kt
index 4843ae7..bb84036 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorKosmos.kt
@@ -18,7 +18,6 @@
import com.android.systemui.bouncer.data.repository.keyguardBouncerRepository
import com.android.systemui.common.ui.data.repository.configurationRepository
-import com.android.systemui.flags.featureFlagsClassic
import com.android.systemui.keyguard.data.repository.keyguardRepository
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.power.domain.interactor.powerInteractor
@@ -33,7 +32,6 @@
repository = keyguardRepository,
commandQueue = commandQueue,
powerInteractor = powerInteractor,
- featureFlags = featureFlagsClassic,
sceneContainerFlags = sceneContainerFlags,
bouncerRepository = keyguardBouncerRepository,
configurationRepository = configurationRepository,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt
index 80c38b2..3c96051 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt
@@ -120,7 +120,6 @@
val testScope = kosmos.testScope
val featureFlags =
FakeFeatureFlagsClassic().apply {
- set(Flags.FACE_AUTH_REFACTOR, false)
set(Flags.FULL_SCREEN_USER_SWITCHER, false)
set(Flags.NSSL_DEBUG_LINES, false)
}
@@ -245,7 +244,6 @@
return KeyguardInteractor(
repository = repository,
commandQueue = FakeCommandQueue(),
- featureFlags = featureFlags,
sceneContainerFlags = sceneContainerFlags,
bouncerRepository = FakeKeyguardBouncerRepository(),
configurationRepository = configurationRepository,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/repository/FakeStatusBarModeRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/repository/FakeStatusBarModeRepository.kt
index f25d282..6069083 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/repository/FakeStatusBarModeRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/repository/FakeStatusBarModeRepository.kt
@@ -16,14 +16,33 @@
package com.android.systemui.statusbar.data.repository
+import android.view.Display
+import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.statusbar.data.model.StatusBarAppearance
import com.android.systemui.statusbar.data.model.StatusBarMode
+import com.google.common.truth.Truth.assertThat
import dagger.Binds
import dagger.Module
import javax.inject.Inject
import kotlinx.coroutines.flow.MutableStateFlow
-class FakeStatusBarModeRepository @Inject constructor() : StatusBarModeRepository {
+@SysUISingleton
+class FakeStatusBarModeRepository @Inject constructor() : StatusBarModeRepositoryStore {
+
+ companion object {
+ const val DISPLAY_ID = Display.DEFAULT_DISPLAY
+ }
+
+ override val defaultDisplay: FakeStatusBarModePerDisplayRepository =
+ FakeStatusBarModePerDisplayRepository()
+
+ override fun forDisplay(displayId: Int): FakeStatusBarModePerDisplayRepository {
+ assertThat(displayId).isEqualTo(DISPLAY_ID)
+ return defaultDisplay
+ }
+}
+
+class FakeStatusBarModePerDisplayRepository : StatusBarModePerDisplayRepository {
override val isTransientShown = MutableStateFlow(false)
override val isInFullscreenMode = MutableStateFlow(false)
override val statusBarAppearance = MutableStateFlow<StatusBarAppearance?>(null)
@@ -39,5 +58,5 @@
@Module
interface FakeStatusBarModeRepositoryModule {
- @Binds fun bindFake(fake: FakeStatusBarModeRepository): StatusBarModeRepository
+ @Binds fun bindFake(fake: FakeStatusBarModeRepository): StatusBarModeRepositoryStore
}
diff --git a/ravenwood/annotations-src/android/ravenwood/annotation/RavenwoodThrow.java b/ravenwood/annotations-src/android/ravenwood/annotation/RavenwoodThrow.java
index a234a9b..0bb1f39 100644
--- a/ravenwood/annotations-src/android/ravenwood/annotation/RavenwoodThrow.java
+++ b/ravenwood/annotations-src/android/ravenwood/annotation/RavenwoodThrow.java
@@ -34,4 +34,13 @@
@Target({METHOD, CONSTRUCTOR})
@Retention(RetentionPolicy.CLASS)
public @interface RavenwoodThrow {
+ /**
+ * One or more classes that aren't yet supported by Ravenwood, which is why this method throws.
+ */
+ Class<?>[] blockedBy() default {};
+
+ /**
+ * General free-form description of why this method throws.
+ */
+ String reason() default "";
}
diff --git a/ravenwood/framework-minus-apex-ravenwood-policies.txt b/ravenwood/framework-minus-apex-ravenwood-policies.txt
index 48e9328..c70c171 100644
--- a/ravenwood/framework-minus-apex-ravenwood-policies.txt
+++ b/ravenwood/framework-minus-apex-ravenwood-policies.txt
@@ -78,6 +78,7 @@
class android.util.UtilConfig stubclass
# Internals
+class com.android.internal.util.FastMath stubclass
class com.android.internal.util.FastPrintWriter stubclass
class com.android.internal.util.GrowingArrayUtils stubclass
class com.android.internal.util.LineBreakBufferedWriter stubclass
@@ -109,6 +110,7 @@
class android.os.PersistableBundle stubclass
# Misc
+class android.os.HandlerExecutor stubclass
class android.os.PatternMatcher stubclass
class android.os.ParcelUuid stubclass
diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java
index 1caef26..be0c09e 100644
--- a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java
+++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java
@@ -16,13 +16,35 @@
package android.platform.test.ravenwood;
+import android.os.HandlerThread;
+import android.os.Looper;
+
+import java.util.Objects;
+
public class RavenwoodRuleImpl {
+ private static final String MAIN_THREAD_NAME = "RavenwoodMain";
+
+ public static boolean isUnderRavenwood() {
+ return true;
+ }
+
public static void init(RavenwoodRule rule) {
android.os.Process.init$ravenwood(rule.mUid, rule.mPid);
android.os.Binder.init$ravenwood();
+
+ if (rule.mProvideMainThread) {
+ final HandlerThread main = new HandlerThread(MAIN_THREAD_NAME);
+ main.start();
+ Looper.setMainLooperForTest(main.getLooper());
+ }
}
public static void reset(RavenwoodRule rule) {
+ if (rule.mProvideMainThread) {
+ Looper.getMainLooper().quit();
+ Looper.clearMainLooperForTest();
+ }
+
android.os.Process.reset$ravenwood();
android.os.Binder.reset$ravenwood();
}
diff --git a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java
index 79f9e58..9db5b98 100644
--- a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java
+++ b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java
@@ -34,6 +34,8 @@
public class RavenwoodRule implements TestRule {
private static AtomicInteger sNextPid = new AtomicInteger(100);
+ private static final boolean IS_UNDER_RAVENWOOD = RavenwoodRuleImpl.isUnderRavenwood();
+
private static final int SYSTEM_UID = 1000;
private static final int NOBODY_UID = 9999;
private static final int FIRST_APPLICATION_UID = 10000;
@@ -45,6 +47,8 @@
int mUid = NOBODY_UID;
int mPid = sNextPid.getAndIncrement();
+ boolean mProvideMainThread = false;
+
public RavenwoodRule() {
}
@@ -72,6 +76,15 @@
return this;
}
+ /**
+ * Configure a "main" thread to be available for the duration of the test, as defined
+ * by {@code Looper.getMainLooper()}. Has no effect under non-Ravenwood environments.
+ */
+ public Builder setProvideMainThread(boolean provideMainThread) {
+ mRule.mProvideMainThread = provideMainThread;
+ return this;
+ }
+
public RavenwoodRule build() {
return mRule;
}
@@ -81,8 +94,7 @@
* Return if the current process is running under a Ravenwood test environment.
*/
public boolean isUnderRavenwood() {
- // TODO: give ourselves a better environment signal
- return System.getProperty("java.class.path").contains("ravenwood");
+ return IS_UNDER_RAVENWOOD;
}
@Override
@@ -90,17 +102,16 @@
return new Statement() {
@Override
public void evaluate() throws Throwable {
- final boolean isUnderRavenwood = isUnderRavenwood();
if (description.getAnnotation(IgnoreUnderRavenwood.class) != null) {
- Assume.assumeFalse(isUnderRavenwood);
+ Assume.assumeFalse(IS_UNDER_RAVENWOOD);
}
- if (isUnderRavenwood) {
+ if (IS_UNDER_RAVENWOOD) {
RavenwoodRuleImpl.init(RavenwoodRule.this);
}
try {
base.evaluate();
} finally {
- if (isUnderRavenwood) {
+ if (IS_UNDER_RAVENWOOD) {
RavenwoodRuleImpl.reset(RavenwoodRule.this);
}
}
diff --git a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java b/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java
index ecaff80..fb71e9d 100644
--- a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java
+++ b/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java
@@ -17,6 +17,10 @@
package android.platform.test.ravenwood;
public class RavenwoodRuleImpl {
+ public static boolean isUnderRavenwood() {
+ return false;
+ }
+
public static void init(RavenwoodRule rule) {
// Must be provided by impl to reference runtime internals
throw new UnsupportedOperationException();
diff --git a/ravenwood/ravenwood-annotation-allowed-classes.txt b/ravenwood/ravenwood-annotation-allowed-classes.txt
index a791f682..07c2cd7c 100644
--- a/ravenwood/ravenwood-annotation-allowed-classes.txt
+++ b/ravenwood/ravenwood-annotation-allowed-classes.txt
@@ -12,9 +12,16 @@
android.os.Binder
android.os.Binder$IdentitySupplier
+android.os.Handler
+android.os.HandlerExecutor
+android.os.HandlerThread
android.os.IBinder
+android.os.Looper
+android.os.Message
+android.os.MessageQueue
android.os.Process
android.os.SystemClock
+android.os.ThreadLocalWorkSource
android.os.UserHandle
android.content.ClipData
@@ -44,3 +51,11 @@
android.text.TextUtils
android.text.TextUtils$SimpleStringSplitter
+
+android.accounts.Account
+
+android.graphics.Insets
+android.graphics.Point
+android.graphics.PointF
+android.graphics.Rect
+android.graphics.RectF
diff --git a/ravenwood/ravenwood-standard-options.txt b/ravenwood/ravenwood-standard-options.txt
index f842f33..8ad21fa 100644
--- a/ravenwood/ravenwood-standard-options.txt
+++ b/ravenwood/ravenwood-standard-options.txt
@@ -7,6 +7,7 @@
# Uncomment below lines to enable each feature.
# --enable-non-stub-method-check
+--no-non-stub-method-check
#--default-method-call-hook
# com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
diff --git a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
index 5635dd5..42ab05f 100644
--- a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
@@ -21,6 +21,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.ActivityOptions;
import android.app.Dialog;
import android.app.PendingIntent;
import android.content.ComponentName;
@@ -205,7 +206,10 @@
intent,
PendingIntent.FLAG_MUTABLE
| PendingIntent.FLAG_ALLOW_UNSAFE_IMPLICIT_INTENT,
- /* options= */ null, UserHandle.CURRENT);
+ ActivityOptions.makeBasic()
+ .setPendingIntentCreatorBackgroundActivityStartMode(
+ ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED)
+ .toBundle(), UserHandle.CURRENT);
if (sDebug) {
Slog.d(TAG, "startActivity add save UI restored with intent=" + intent);
}
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index b9c269c..71a1f01 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -75,7 +75,6 @@
import android.companion.IOnTransportsChangedListener;
import android.companion.ISystemDataTransferCallback;
import android.companion.datatransfer.PermissionSyncRequest;
-import android.companion.utils.FeatureUtils;
import android.content.ComponentName;
import android.content.Context;
import android.content.SharedPreferences;
@@ -829,11 +828,6 @@
@Override
public PendingIntent buildPermissionTransferUserConsentIntent(String packageName,
int userId, int associationId) {
- if (!FeatureUtils.isPermSyncEnabled()) {
- throw new UnsupportedOperationException("Calling"
- + " buildPermissionTransferUserConsentIntent, but this API is disabled by"
- + " the system.");
- }
return mSystemDataTransferProcessor.buildPermissionTransferUserConsentIntent(
packageName, userId, associationId);
}
@@ -841,10 +835,6 @@
@Override
public void startSystemDataTransfer(String packageName, int userId, int associationId,
ISystemDataTransferCallback callback) {
- if (!FeatureUtils.isPermSyncEnabled()) {
- throw new UnsupportedOperationException("Calling startSystemDataTransfer, but this"
- + " API is disabled by the system.");
- }
mSystemDataTransferProcessor.startSystemDataTransfer(packageName, userId,
associationId, callback);
}
diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
index 215970e..e51ef29 100644
--- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
@@ -864,6 +864,23 @@
}
@Override
+ public @NonNull Set<String> getAllPersistentDeviceIds() {
+ Set<String> persistentIds = new ArraySet<>();
+ synchronized (mVirtualDeviceManagerLock) {
+ for (int i = 0; i < mActiveAssociations.size(); ++i) {
+ AssociationInfo associationInfo = mActiveAssociations.get(i);
+ if (VIRTUAL_DEVICE_COMPANION_DEVICE_PROFILES.contains(
+ associationInfo.getDeviceProfile())) {
+ persistentIds.add(
+ VirtualDeviceImpl.createPersistentDeviceId(
+ associationInfo.getId()));
+ }
+ }
+ }
+ return persistentIds;
+ }
+
+ @Override
public void registerAppsOnVirtualDeviceListener(
@NonNull AppsOnVirtualDeviceListener listener) {
synchronized (mVirtualDeviceManagerLock) {
diff --git a/services/companion/java/com/android/server/companion/virtual/camera/VirtualCameraConversionUtil.java b/services/companion/java/com/android/server/companion/virtual/camera/VirtualCameraConversionUtil.java
index a570d09..6940ffe 100644
--- a/services/companion/java/com/android/server/companion/virtual/camera/VirtualCameraConversionUtil.java
+++ b/services/companion/java/com/android/server/companion/virtual/camera/VirtualCameraConversionUtil.java
@@ -69,6 +69,11 @@
}
@Override
+ public void onProcessCaptureRequest(int streamId, int frameId) throws RemoteException {
+ camera.onProcessCaptureRequest(streamId, frameId, /*metadata=*/ null);
+ }
+
+ @Override
public void onStreamClosed(int streamId) throws RemoteException {
camera.onStreamClosed(streamId);
}
diff --git a/services/core/java/com/android/server/BinaryTransparencyService.java b/services/core/java/com/android/server/BinaryTransparencyService.java
index 7907d61..77b6d583 100644
--- a/services/core/java/com/android/server/BinaryTransparencyService.java
+++ b/services/core/java/com/android/server/BinaryTransparencyService.java
@@ -1182,8 +1182,8 @@
// we are only interested in doing things at PHASE_BOOT_COMPLETED
if (phase == PHASE_BOOT_COMPLETED) {
- Slog.i(TAG, "Boot completed. Getting VBMeta Digest.");
- getVBMetaDigestInformation();
+ Slog.i(TAG, "Boot completed. Getting boot integrity data.");
+ collectBootIntegrityInfo();
// Log to statsd
// TODO(b/264061957): For now, biometric system properties are always collected if users
@@ -1458,10 +1458,19 @@
}
}
- private void getVBMetaDigestInformation() {
+ private void collectBootIntegrityInfo() {
mVbmetaDigest = SystemProperties.get(SYSPROP_NAME_VBETA_DIGEST, VBMETA_DIGEST_UNAVAILABLE);
Slog.d(TAG, String.format("VBMeta Digest: %s", mVbmetaDigest));
FrameworkStatsLog.write(FrameworkStatsLog.VBMETA_DIGEST_REPORTED, mVbmetaDigest);
+
+ if (android.security.Flags.binaryTransparencySepolicyHash()) {
+ byte[] sepolicyHash = PackageUtils.computeSha256DigestForLargeFileAsBytes(
+ "/sys/fs/selinux/policy", PackageUtils.createLargeFileBuffer());
+ String sepolicyHashEncoded = HexEncoding.encodeToString(sepolicyHash, false);
+ Slog.d(TAG, "sepolicy hash: " + sepolicyHashEncoded);
+ FrameworkStatsLog.write(FrameworkStatsLog.BOOT_INTEGRITY_INFO_REPORTED,
+ sepolicyHashEncoded, mVbmetaDigest);
+ }
}
/**
diff --git a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
index 5b54561..e07631c 100644
--- a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
+++ b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
@@ -193,6 +193,12 @@
private @Nullable BroadcastProcessQueue mRunningColdStart;
/**
+ * Indicates whether we have queued a message to check pending cold start validity.
+ */
+ @GuardedBy("mService")
+ private boolean mCheckPendingColdStartQueued;
+
+ /**
* Collection of latches waiting for device to reach specific state. The
* first argument is a function to test for the desired state, and the
* second argument is the latch to release once that state is reached.
@@ -302,7 +308,11 @@
return true;
}
case MSG_CHECK_PENDING_COLD_START_VALIDITY: {
- checkPendingColdStartValidity();
+ synchronized (mService) {
+ /* Clear this as we have just received the broadcast. */
+ mCheckPendingColdStartQueued = false;
+ checkPendingColdStartValidityLocked();
+ }
return true;
}
case MSG_PROCESS_FREEZABLE_CHANGED: {
@@ -549,7 +559,7 @@
mService.updateOomAdjPendingTargetsLocked(OOM_ADJ_REASON_START_RECEIVER);
}
- checkPendingColdStartValidity();
+ checkPendingColdStartValidityLocked();
checkAndRemoveWaitingFor();
traceEnd(cookie);
@@ -573,22 +583,24 @@
enqueueUpdateRunningList();
}
- private void checkPendingColdStartValidity() {
+ @GuardedBy("mService")
+ private void checkPendingColdStartValidityLocked() {
// There are a few cases where a starting process gets killed but AMS doesn't report
// this event. So, once we start waiting for a pending cold start, periodically check
// if the pending start is still valid and if not, clear it so that the queue doesn't
// keep waiting for the process start forever.
- synchronized (mService) {
- // If there is no pending cold start, then nothing to do.
- if (mRunningColdStart == null) {
- return;
- }
- if (isPendingColdStartValid()) {
+ // If there is no pending cold start, then nothing to do.
+ if (mRunningColdStart == null) {
+ return;
+ }
+ if (isPendingColdStartValid()) {
+ if (!mCheckPendingColdStartQueued) {
mLocalHandler.sendEmptyMessageDelayed(MSG_CHECK_PENDING_COLD_START_VALIDITY,
mConstants.PENDING_COLD_START_CHECK_INTERVAL_MILLIS);
- } else {
- clearInvalidPendingColdStart();
+ mCheckPendingColdStartQueued = true;
}
+ } else {
+ clearInvalidPendingColdStart();
}
}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 1ef4333..e7ea0be 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -154,7 +154,6 @@
import android.media.projection.IMediaProjection;
import android.media.projection.IMediaProjectionCallback;
import android.media.projection.IMediaProjectionManager;
-import android.media.session.MediaSessionManager;
import android.net.Uri;
import android.os.Binder;
import android.os.Build;
@@ -312,9 +311,6 @@
private final ContentResolver mContentResolver;
private final AppOpsManager mAppOps;
- /** do not use directly, use getMediaSessionManager() which handles lazy initialization */
- @Nullable private volatile MediaSessionManager mMediaSessionManager;
-
// the platform type affects volume and silent mode behavior
private final int mPlatformType;
@@ -945,8 +941,6 @@
private final SoundDoseHelper mSoundDoseHelper;
- private final HardeningEnforcer mHardeningEnforcer;
-
private final Object mSupportedSystemUsagesLock = new Object();
@GuardedBy("mSupportedSystemUsagesLock")
private @AttributeSystemUsage int[] mSupportedSystemUsages =
@@ -1321,8 +1315,6 @@
mDisplayManager = context.getSystemService(DisplayManager.class);
mMusicFxHelper = new MusicFxHelper(mContext, mAudioHandler);
-
- mHardeningEnforcer = new HardeningEnforcer(mContext, isPlatformAutomotive());
}
private void initVolumeStreamStates() {
@@ -1394,6 +1386,7 @@
// check on volume initialization
checkVolumeRangeInitialization("AudioService()");
+
}
private SubscriptionManager.OnSubscriptionsChangedListener mSubscriptionChangedListener =
@@ -1406,14 +1399,6 @@
}
};
- private MediaSessionManager getMediaSessionManager() {
- if (mMediaSessionManager == null) {
- mMediaSessionManager = (MediaSessionManager) mContext
- .getSystemService(Context.MEDIA_SESSION_SERVICE);
- }
- return mMediaSessionManager;
- }
-
/**
* Initialize intent receives and settings observers for this service.
* Must be called after createStreamStates() as the handling of some events
@@ -3442,10 +3427,6 @@
* Part of service interface, check permissions here */
public void adjustStreamVolumeWithAttribution(int streamType, int direction, int flags,
String callingPackage, String attributionTag) {
- if (mHardeningEnforcer.blockVolumeMethod(
- HardeningEnforcer.METHOD_AUDIO_MANAGER_ADJUST_STREAM_VOLUME)) {
- return;
- }
if ((streamType == AudioManager.STREAM_ACCESSIBILITY) && !canChangeAccessibilityVolume()) {
Log.w(TAG, "Trying to call adjustStreamVolume() for a11y without"
+ "CHANGE_ACCESSIBILITY_VOLUME / callingPackage=" + callingPackage);
@@ -3999,7 +3980,8 @@
}
setStreamVolume(groupedStream, index, flags, /*device*/ null,
callingPackage, callingPackage,
- attributionTag, Binder.getCallingUid(), true /*hasModifyAudioSettings*/);
+ attributionTag, Binder.getCallingUid(), true /*hasModifyAudioSettings*/,
+ true /*canChangeMuteAndUpdateController*/);
}
}
@@ -4118,7 +4100,9 @@
setStreamVolumeWithAttributionInt(vi.getStreamType(),
mStreamStates[vi.getStreamType()].getMinIndex(),
/*flags*/ 0,
- ada, callingPackage, null);
+ ada, callingPackage, null,
+ //TODO handle unmuting of current audio device
+ false /*canChangeMuteAndUpdateController*/);
return;
}
@@ -4144,7 +4128,8 @@
}
}
setStreamVolumeWithAttributionInt(vi.getStreamType(), index, /*flags*/ 0,
- ada, callingPackage, null);
+ ada, callingPackage, null,
+ false /*canChangeMuteAndUpdateController*/);
}
/** Retain API for unsupported app usage */
@@ -4222,12 +4207,8 @@
* Part of service interface, check permissions here */
public void setStreamVolumeWithAttribution(int streamType, int index, int flags,
String callingPackage, String attributionTag) {
- if (mHardeningEnforcer.blockVolumeMethod(
- HardeningEnforcer.METHOD_AUDIO_MANAGER_SET_STREAM_VOLUME)) {
- return;
- }
setStreamVolumeWithAttributionInt(streamType, index, flags, /*device*/ null,
- callingPackage, attributionTag);
+ callingPackage, attributionTag, true /*canChangeMuteAndUpdateController*/);
}
/**
@@ -4240,10 +4221,18 @@
* for which volume is being changed
* @param callingPackage client side-provided package name of caller, not to be trusted
* @param attributionTag client side-provided attribution name, not to be trusted
+ * @param canChangeMuteAndUpdateController true if the calling method is a path where
+ * the volume change is allowed to update the mute state as well as update
+ * the volume controller (the UI). This is intended to be true for a call coming
+ * from AudioManager.setStreamVolume (which is here
+ * {@link #setStreamVolumeForUid(int, int, int, String, int, int, UserHandle, int)},
+ * and false when coming from AudioDeviceVolumeManager.setDeviceVolume (which is here
+ * {@link #setDeviceVolume(VolumeInfo, AudioDeviceAttributes, String)}
*/
protected void setStreamVolumeWithAttributionInt(int streamType, int index, int flags,
- @Nullable AudioDeviceAttributes device,
- String callingPackage, String attributionTag) {
+ @Nullable AudioDeviceAttributes ada,
+ String callingPackage, String attributionTag,
+ boolean canChangeMuteAndUpdateController) {
if ((streamType == AudioManager.STREAM_ACCESSIBILITY) && !canChangeAccessibilityVolume()) {
Log.w(TAG, "Trying to call setStreamVolume() for a11y without"
+ " CHANGE_ACCESSIBILITY_VOLUME callingPackage=" + callingPackage);
@@ -4266,15 +4255,18 @@
return;
}
- if (device == null) {
+ if (ada == null) {
// call was already logged in setDeviceVolume()
+ final int deviceType = getDeviceForStream(streamType);
sVolumeLogger.enqueue(new VolumeEvent(VolumeEvent.VOL_SET_STREAM_VOL, streamType,
- index/*val1*/, flags/*val2*/, getStreamVolume(streamType) /*val3*/,
+ index/*val1*/, flags/*val2*/, getStreamVolume(streamType, deviceType) /*val3*/,
callingPackage));
+ ada = new AudioDeviceAttributes(deviceType /*nativeType*/, "" /*address*/);
}
- setStreamVolume(streamType, index, flags, device,
+ setStreamVolume(streamType, index, flags, ada,
callingPackage, callingPackage, attributionTag,
- Binder.getCallingUid(), callingOrSelfHasAudioSettingsPermission());
+ Binder.getCallingUid(), callingOrSelfHasAudioSettingsPermission(),
+ canChangeMuteAndUpdateController);
}
@android.annotation.EnforcePermission(android.Manifest.permission.ACCESS_ULTRASOUND)
@@ -4562,9 +4554,11 @@
}
private void setStreamVolume(int streamType, int index, int flags,
- @Nullable AudioDeviceAttributes ada,
+ @NonNull AudioDeviceAttributes ada,
String callingPackage, String caller, String attributionTag, int uid,
- boolean hasModifyAudioSettings) {
+ boolean hasModifyAudioSettings,
+ boolean canChangeMuteAndUpdateController) {
+
if (DEBUG_VOL) {
Log.d(TAG, "setStreamVolume(stream=" + streamType+", index=" + index
+ ", dev=" + ada
@@ -4578,9 +4572,7 @@
int streamTypeAlias = mStreamVolumeAlias[streamType];
VolumeStreamState streamState = mStreamStates[streamTypeAlias];
- final int device = (ada == null)
- ? getDeviceForStream(streamType)
- : ada.getInternalType();
+ final int device = ada.getInternalType();
int oldIndex;
// skip a2dp absolute volume control request when the device
@@ -4667,7 +4659,7 @@
onSetStreamVolume(streamType, index, flags, device, caller, hasModifyAudioSettings,
// ada is non-null when called from setDeviceVolume,
// which shouldn't update the mute state
- ada == null /*canChangeMute*/);
+ canChangeMuteAndUpdateController /*canChangeMute*/);
index = mStreamStates[streamType].getIndex(device);
}
@@ -4677,7 +4669,7 @@
maybeSendSystemAudioStatusCommand(false);
}
}
- if (ada == null) {
+ if (canChangeMuteAndUpdateController) {
// only non-null when coming here from setDeviceVolume
// TODO change test to check early if device is current device or not
sendVolumeUpdate(streamType, oldIndex, index, flags, device);
@@ -5080,7 +5072,6 @@
/** @see AudioManager#setMasterMute(boolean, int) */
public void setMasterMute(boolean mute, int flags, String callingPackage, int userId,
String attributionTag) {
-
super.setMasterMute_enforcePermission();
setMasterMuteInternal(mute, flags, callingPackage,
@@ -5091,6 +5082,10 @@
public int getStreamVolume(int streamType) {
ensureValidStreamType(streamType);
int device = getDeviceForStream(streamType);
+ return getStreamVolume(streamType, device);
+ }
+
+ private int getStreamVolume(int streamType, int device) {
synchronized (VolumeStreamState.class) {
int index = mStreamStates[streamType].getIndex(device);
@@ -5446,10 +5441,6 @@
}
public void setRingerModeExternal(int ringerMode, String caller) {
- if (mHardeningEnforcer.blockVolumeMethod(
- HardeningEnforcer.METHOD_AUDIO_MANAGER_SET_RINGER_MODE)) {
- return;
- }
if (isAndroidNPlus(caller) && wouldToggleZenMode(ringerMode)
&& !mNm.isNotificationPolicyAccessGrantedForPackage(caller)) {
throw new SecurityException("Not allowed to change Do Not Disturb state");
@@ -6202,35 +6193,6 @@
AudioDeviceVolumeManager.ADJUST_MODE_NORMAL);
}
- /**
- * @see AudioManager#adjustVolume(int, int)
- * This method is redirected from AudioManager to AudioService for API hardening rules
- * enforcement then to MediaSession for implementation.
- */
- @Override
- public void adjustVolume(int direction, int flags) {
- if (mHardeningEnforcer.blockVolumeMethod(
- HardeningEnforcer.METHOD_AUDIO_MANAGER_ADJUST_VOLUME)) {
- return;
- }
- getMediaSessionManager().dispatchAdjustVolume(AudioManager.USE_DEFAULT_STREAM_TYPE,
- direction, flags);
- }
-
- /**
- * @see AudioManager#adjustSuggestedStreamVolume(int, int, int)
- * This method is redirected from AudioManager to AudioService for API hardening rules
- * enforcement then to MediaSession for implementation.
- */
- @Override
- public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags) {
- if (mHardeningEnforcer.blockVolumeMethod(
- HardeningEnforcer.METHOD_AUDIO_MANAGER_ADJUST_SUGGESTED_STREAM_VOLUME)) {
- return;
- }
- getMediaSessionManager().dispatchAdjustVolume(suggestedStreamType, direction, flags);
- }
-
/** @see AudioManager#setStreamVolumeForUid(int, int, int, String, int, int, int) */
@Override
public void setStreamVolumeForUid(int streamType, int index, int flags,
@@ -6242,7 +6204,8 @@
setStreamVolume(streamType, index, flags, /*device*/ null,
packageName, packageName, null, uid,
- hasAudioSettingsPermission(uid, pid));
+ hasAudioSettingsPermission(uid, pid),
+ true /*canChangeMuteAndUpdateController*/);
}
//==========================================================================================
diff --git a/services/core/java/com/android/server/audio/HardeningEnforcer.java b/services/core/java/com/android/server/audio/HardeningEnforcer.java
deleted file mode 100644
index 4ceb83b2..0000000
--- a/services/core/java/com/android/server/audio/HardeningEnforcer.java
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright 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.audio;
-
-import static android.media.audio.Flags.autoPublicVolumeApiHardening;
-
-import android.Manifest;
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.media.AudioManager;
-import android.os.Binder;
-import android.os.UserHandle;
-import android.text.TextUtils;
-import android.util.Log;
-
-/**
- * Class to encapsulate all audio API hardening operations
- */
-public class HardeningEnforcer {
-
- private static final String TAG = "AS.HardeningEnforcer";
-
- final Context mContext;
- final boolean mIsAutomotive;
-
- /**
- * Matches calls from {@link AudioManager#setStreamVolume(int, int, int)}
- */
- public static final int METHOD_AUDIO_MANAGER_SET_STREAM_VOLUME = 100;
- /**
- * Matches calls from {@link AudioManager#adjustVolume(int, int)}
- */
- public static final int METHOD_AUDIO_MANAGER_ADJUST_VOLUME = 101;
- /**
- * Matches calls from {@link AudioManager#adjustSuggestedStreamVolume(int, int, int)}
- */
- public static final int METHOD_AUDIO_MANAGER_ADJUST_SUGGESTED_STREAM_VOLUME = 102;
- /**
- * Matches calls from {@link AudioManager#adjustStreamVolume(int, int, int)}
- */
- public static final int METHOD_AUDIO_MANAGER_ADJUST_STREAM_VOLUME = 103;
- /**
- * Matches calls from {@link AudioManager#setRingerMode(int)}
- */
- public static final int METHOD_AUDIO_MANAGER_SET_RINGER_MODE = 200;
-
- public HardeningEnforcer(Context ctxt, boolean isAutomotive) {
- mContext = ctxt;
- mIsAutomotive = isAutomotive;
- }
-
- /**
- * Checks whether the call in the current thread should be allowed or blocked
- * @param volumeMethod name of the method to check, for logging purposes
- * @return false if the method call is allowed, true if it should be a no-op
- */
- protected boolean blockVolumeMethod(int volumeMethod) {
- // for Auto, volume methods require MODIFY_AUDIO_SETTINGS_PRIVILEGED
- if (mIsAutomotive) {
- if (!autoPublicVolumeApiHardening()) {
- // automotive hardening flag disabled, no blocking on auto
- return false;
- }
- if (mContext.checkCallingOrSelfPermission(
- Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED)
- == PackageManager.PERMISSION_GRANTED) {
- return false;
- }
- if (Binder.getCallingUid() < UserHandle.AID_APP_START) {
- return false;
- }
- // TODO metrics?
- // TODO log for audio dumpsys?
- Log.e(TAG, "Preventing volume method " + volumeMethod + " for "
- + getPackNameForUid(Binder.getCallingUid()));
- return true;
- }
- // not blocking
- return false;
- }
-
- private String getPackNameForUid(int uid) {
- final long token = Binder.clearCallingIdentity();
- try {
- final String[] names = mContext.getPackageManager().getPackagesForUid(uid);
- if (names == null
- || names.length == 0
- || TextUtils.isEmpty(names[0])) {
- return "[" + uid + "]";
- }
- return names[0];
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
-}
diff --git a/services/core/java/com/android/server/audio/SoundDoseHelper.java b/services/core/java/com/android/server/audio/SoundDoseHelper.java
index 793752f..c72632f 100644
--- a/services/core/java/com/android/server/audio/SoundDoseHelper.java
+++ b/services/core/java/com/android/server/audio/SoundDoseHelper.java
@@ -1297,7 +1297,8 @@
}
final int index = safeMediaVolumeIndex(nativeDeviceType);
mAudioService.setStreamVolumeWithAttributionInt(STREAM_MUSIC, index / 10, /*flags*/ 0, ada,
- mContext.getOpPackageName(), /*attributionTag=*/null);
+ mContext.getOpPackageName(), /*attributionTag=*/null,
+ true /*canChangeMuteAndUpdateController*/);
}
// StreamVolumeCommand contains the information needed to defer the process of
diff --git a/services/core/java/com/android/server/audio/SpatializerHelper.java b/services/core/java/com/android/server/audio/SpatializerHelper.java
index ea92154..61e4f36 100644
--- a/services/core/java/com/android/server/audio/SpatializerHelper.java
+++ b/services/core/java/com/android/server/audio/SpatializerHelper.java
@@ -19,6 +19,9 @@
import static android.media.AudioManager.AUDIO_DEVICE_CATEGORY_HEADPHONES;
import static android.media.AudioManager.AUDIO_DEVICE_CATEGORY_UNKNOWN;
import static android.media.AudioSystem.isBluetoothDevice;
+import static android.media.AudioSystem.isBluetoothLeDevice;
+
+import static com.android.media.audio.Flags.dsaOverBtLeAudio;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -1625,10 +1628,10 @@
}
private int getHeadSensorHandleUpdateTracker() {
- int headHandle = -1;
+ Sensor htSensor = null;
if (sRoutingDevices.isEmpty()) {
logloge("getHeadSensorHandleUpdateTracker: no device, no head tracker");
- return headHandle;
+ return -1;
}
final AudioDeviceAttributes currentDevice = sRoutingDevices.get(0);
List<String> deviceAddresses = mAudioService.getDeviceAddresses(currentDevice);
@@ -1642,27 +1645,86 @@
for (String address : deviceAddresses) {
UUID routingDeviceUuid = UuidUtils.uuidFromAudioDeviceAttributes(
new AudioDeviceAttributes(currentDevice.getInternalType(), address));
- for (Sensor sensor : sensors) {
- final UUID uuid = sensor.getUuid();
- if (uuid.equals(routingDeviceUuid)) {
- headHandle = sensor.getHandle();
- if (!setHasHeadTracker(currentDevice)) {
- headHandle = -1;
+ if (dsaOverBtLeAudio()) {
+ for (Sensor sensor : sensors) {
+ final UUID uuid = sensor.getUuid();
+ if (uuid.equals(routingDeviceUuid)) {
+ htSensor = sensor;
+ HeadtrackerInfo info = new HeadtrackerInfo(sensor);
+ if (isBluetoothLeDevice(currentDevice.getInternalType())) {
+ if (info.getMajorVersion() == 2) {
+ // Version 2 is used only by LE Audio profile
+ break;
+ }
+ // we do not break, as this could be a match on the A2DP sensor
+ // for a dual mode headset.
+ } else if (info.getMajorVersion() == 1) {
+ // Version 1 is used only by A2DP profile
+ break;
+ }
}
+ if (htSensor == null && uuid.equals(UuidUtils.STANDALONE_UUID)) {
+ htSensor = sensor;
+ // we do not break, perhaps we find a head tracker on device.
+ }
+ }
+ if (htSensor != null) {
+ if (htSensor.getUuid().equals(UuidUtils.STANDALONE_UUID)) {
+ break;
+ }
+ if (setHasHeadTracker(currentDevice)) {
+ break;
+ } else {
+ htSensor = null;
+ }
+ }
+ } else {
+ for (Sensor sensor : sensors) {
+ final UUID uuid = sensor.getUuid();
+ if (uuid.equals(routingDeviceUuid)) {
+ htSensor = sensor;
+ if (!setHasHeadTracker(currentDevice)) {
+ htSensor = null;
+ }
+ break;
+ }
+ if (uuid.equals(UuidUtils.STANDALONE_UUID)) {
+ htSensor = sensor;
+ // we do not break, perhaps we find a head tracker on device.
+ }
+ }
+ if (htSensor != null) {
break;
}
- if (uuid.equals(UuidUtils.STANDALONE_UUID)) {
- headHandle = sensor.getHandle();
- // we do not break, perhaps we find a head tracker on device.
- }
- }
- if (headHandle != -1) {
- break;
}
}
- return headHandle;
+ return htSensor != null ? htSensor.getHandle() : -1;
}
+ /**
+ * Contains the information parsed from the head tracker sensor version.
+ * See platform/hardware/libhardware/modules/sensors/dynamic_sensor/HidRawSensor.h
+ * for the definition of version and capability fields.
+ */
+ private static class HeadtrackerInfo {
+ private final int mVersion;
+ HeadtrackerInfo(Sensor sensor) {
+ mVersion = sensor.getVersion();
+ }
+ int getMajorVersion() {
+ return (mVersion & 0xFF000000) >> 24;
+ }
+ int getMinorVersion() {
+ return (mVersion & 0xFF0000) >> 16;
+ }
+ boolean hasAclTransport() {
+ return getMajorVersion() == 2 ? ((mVersion & 0x1) != 0) : false;
+ }
+ boolean hasIsoTransport() {
+ return getMajorVersion() == 2 ? ((mVersion & 0x2) != 0) : false;
+ }
+ };
+
private int getScreenSensorHandle() {
int screenHandle = -1;
Sensor screenSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR);
diff --git a/services/core/java/com/android/server/companion/virtual/VirtualDeviceManagerInternal.java b/services/core/java/com/android/server/companion/virtual/VirtualDeviceManagerInternal.java
index c629b2b..be78ea2 100644
--- a/services/core/java/com/android/server/companion/virtual/VirtualDeviceManagerInternal.java
+++ b/services/core/java/com/android/server/companion/virtual/VirtualDeviceManagerInternal.java
@@ -157,4 +157,10 @@
* @see VirtualDevice#getPersistentDeviceId()
*/
public abstract @Nullable String getPersistentIdForDevice(int deviceId);
+
+ /**
+ * Returns all current persistent device IDs, including the ones for which no virtual device
+ * exists, as long as one may have existed or can be created.
+ */
+ public abstract @NonNull Set<String> getAllPersistentDeviceIds();
}
diff --git a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
index 99a5398..debf828 100644
--- a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
+++ b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
@@ -33,6 +33,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.display.BrightnessSynchronizer;
+import com.android.internal.display.BrightnessUtils;
import com.android.internal.util.Preconditions;
import com.android.server.display.utils.Plog;
import com.android.server.display.whitebalance.DisplayWhiteBalanceController;
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index e99f82a..6a7c17d 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -576,7 +576,8 @@
foldSettingProvider,
mDisplayDeviceRepo, new LogicalDisplayListener(), mSyncRoot, mHandler, mFlags);
mDisplayModeDirector = new DisplayModeDirector(context, mHandler, mFlags);
- mBrightnessSynchronizer = new BrightnessSynchronizer(mContext);
+ mBrightnessSynchronizer = new BrightnessSynchronizer(mContext,
+ mFlags.isBrightnessIntRangeUserPerceptionEnabled());
Resources resources = mContext.getResources();
mDefaultDisplayDefaultColorMode = mContext.getResources().getInteger(
com.android.internal.R.integer.config_defaultDisplayDefaultColorMode);
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index f3d761a..f09fcea 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -20,6 +20,7 @@
import android.animation.ObjectAnimator;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SuppressLint;
import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.content.Context;
@@ -3252,12 +3253,15 @@
}
}
+ @SuppressLint("AndroidFrameworkRequiresPermission")
private void noteScreenBrightness(float brightness) {
if (mBatteryStats != null) {
try {
// TODO(brightnessfloat): change BatteryStats to use float
- mBatteryStats.noteScreenBrightness(BrightnessSynchronizer.brightnessFloatToInt(
- brightness));
+ int brightnessInt = mFlags.isBrightnessIntRangeUserPerceptionEnabled()
+ ? BrightnessSynchronizer.brightnessFloatToIntSetting(mContext, brightness)
+ : BrightnessSynchronizer.brightnessFloatToInt(brightness);
+ mBatteryStats.noteScreenBrightness(brightnessInt);
} catch (RemoteException e) {
// same process
}
diff --git a/services/core/java/com/android/server/display/DisplayPowerController2.java b/services/core/java/com/android/server/display/DisplayPowerController2.java
index d4e0cbb..5310e43 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController2.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController2.java
@@ -19,6 +19,7 @@
import android.animation.Animator;
import android.animation.ObjectAnimator;
import android.annotation.Nullable;
+import android.annotation.SuppressLint;
import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.content.Context;
@@ -2636,12 +2637,15 @@
}
}
+ @SuppressLint("AndroidFrameworkRequiresPermission")
private void noteScreenBrightness(float brightness) {
if (mBatteryStats != null) {
try {
// TODO(brightnessfloat): change BatteryStats to use float
- mBatteryStats.noteScreenBrightness(BrightnessSynchronizer.brightnessFloatToInt(
- brightness));
+ int brightnessInt = mFlags.isBrightnessIntRangeUserPerceptionEnabled()
+ ? BrightnessSynchronizer.brightnessFloatToIntSetting(mContext, brightness)
+ : BrightnessSynchronizer.brightnessFloatToInt(brightness);
+ mBatteryStats.noteScreenBrightness(brightnessInt);
} catch (RemoteException e) {
// same process
}
diff --git a/services/core/java/com/android/server/display/RampAnimator.java b/services/core/java/com/android/server/display/RampAnimator.java
index 5ba042c..e38c2c5 100644
--- a/services/core/java/com/android/server/display/RampAnimator.java
+++ b/services/core/java/com/android/server/display/RampAnimator.java
@@ -20,6 +20,8 @@
import android.util.FloatProperty;
import android.view.Choreographer;
+import com.android.internal.display.BrightnessUtils;
+
/**
* A custom animator that progressively updates a property value at
* a given variable rate until it reaches a particular target value.
diff --git a/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java b/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java
index b1c0762..aa80612 100644
--- a/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java
+++ b/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java
@@ -82,6 +82,10 @@
com.android.graphics.surfaceflinger.flags.Flags.FLAG_ENABLE_SMALL_AREA_DETECTION,
com.android.graphics.surfaceflinger.flags.Flags::enableSmallAreaDetection);
+ private final FlagState mBrightnessIntRangeUserPerceptionFlagState = new FlagState(
+ Flags.FLAG_BRIGHTNESS_INT_RANGE_USER_PERCEPTION,
+ Flags::brightnessIntRangeUserPerception);
+
/** Returns whether connected display management is enabled or not. */
public boolean isConnectedDisplayManagementEnabled() {
return mConnectedDisplayManagementFlagState.isEnabled();
@@ -162,6 +166,10 @@
return mSmallAreaDetectionFlagState.isEnabled();
}
+ public boolean isBrightnessIntRangeUserPerceptionEnabled() {
+ return mBrightnessIntRangeUserPerceptionFlagState.isEnabled();
+ }
+
/**
* dumps all flagstates
* @param pw printWriter
@@ -179,6 +187,7 @@
pw.println(" " + mNbmControllerFlagState);
pw.println(" " + mPowerThrottlingClamperFlagState);
pw.println(" " + mSmallAreaDetectionFlagState);
+ pw.println(" " + mBrightnessIntRangeUserPerceptionFlagState);
}
private static class FlagState {
diff --git a/services/core/java/com/android/server/display/feature/display_flags.aconfig b/services/core/java/com/android/server/display/feature/display_flags.aconfig
index 9ab9c9d..e28b415 100644
--- a/services/core/java/com/android/server/display/feature/display_flags.aconfig
+++ b/services/core/java/com/android/server/display/feature/display_flags.aconfig
@@ -104,3 +104,11 @@
bug: "211737588"
is_fixed_read_only: true
}
+
+flag {
+ name: "brightness_int_range_user_perception"
+ namespace: "display_manager"
+ description: "Feature flag for converting the brightness integer range to the user perception scale"
+ bug: "183655602"
+ is_fixed_read_only: true
+}
diff --git a/services/core/java/com/android/server/display/mode/DisplayModeDirector.java b/services/core/java/com/android/server/display/mode/DisplayModeDirector.java
index fb6c9e3..9587f55 100644
--- a/services/core/java/com/android/server/display/mode/DisplayModeDirector.java
+++ b/services/core/java/com/android/server/display/mode/DisplayModeDirector.java
@@ -21,8 +21,8 @@
import static android.os.PowerManager.BRIGHTNESS_INVALID_FLOAT;
import static android.view.Display.Mode.INVALID_MODE_ID;
+import static com.android.internal.display.RefreshRateSettingsUtils.findHighestRefreshRate;
import static com.android.server.display.DisplayDeviceConfig.DEFAULT_LOW_REFRESH_RATE;
-import static com.android.internal.display.RefreshRateSettingsUtils.findHighestRefreshRateForDefaultDisplay;
import android.annotation.IntegerRes;
import android.annotation.NonNull;
@@ -959,11 +959,16 @@
}
@VisibleForTesting
+ DisplayObserver getDisplayObserver() {
+ return mDisplayObserver;
+ }
+
+ @VisibleForTesting
DesiredDisplayModeSpecs getDesiredDisplayModeSpecsWithInjectedFpsSettings(
float minRefreshRate, float peakRefreshRate, float defaultRefreshRate) {
synchronized (mLock) {
- mSettingsObserver.updateRefreshRateSettingLocked(
- minRefreshRate, peakRefreshRate, defaultRefreshRate);
+ mSettingsObserver.updateRefreshRateSettingLocked(minRefreshRate, peakRefreshRate,
+ defaultRefreshRate, Display.DEFAULT_DISPLAY);
return getDesiredDisplayModeSpecs(Display.DEFAULT_DISPLAY);
}
}
@@ -1297,9 +1302,23 @@
mBrightnessObserver.onLowPowerModeEnabledLocked(inLowPowerMode);
}
+ /**
+ * Update refresh rate settings for all displays
+ */
private void updateRefreshRateSettingLocked() {
+ Display[] displays = mInjector.getDisplays();
+ for (int i = 0; i < displays.length; i++) {
+ updateRefreshRateSettingLocked(displays[i].getDisplayId());
+ }
+ }
+
+ /**
+ * Update refresh rate settings for a specific display
+ * @param displayId The display ID
+ */
+ private void updateRefreshRateSettingLocked(int displayId) {
final ContentResolver cr = mContext.getContentResolver();
- float highestRefreshRate = findHighestRefreshRateForDefaultDisplay(mContext);
+ float highestRefreshRate = findHighestRefreshRate(mContext, displayId);
float minRefreshRate = Settings.System.getFloatForUser(cr,
Settings.System.MIN_REFRESH_RATE, 0f, cr.getUserId());
@@ -1327,11 +1346,12 @@
}
}
- updateRefreshRateSettingLocked(minRefreshRate, peakRefreshRate, mDefaultRefreshRate);
+ updateRefreshRateSettingLocked(minRefreshRate, peakRefreshRate, mDefaultRefreshRate,
+ displayId);
}
- private void updateRefreshRateSettingLocked(
- float minRefreshRate, float peakRefreshRate, float defaultRefreshRate) {
+ private void updateRefreshRateSettingLocked(float minRefreshRate, float peakRefreshRate,
+ float defaultRefreshRate, int displayId) {
// TODO(b/156304339): The logic in here, aside from updating the refresh rate votes, is
// used to predict if we're going to be doing frequent refresh rate switching, and if
// so, enable the brightness observer. The logic here is more complicated and fragile
@@ -1339,9 +1359,9 @@
Vote peakVote = peakRefreshRate == 0f
? null
: Vote.forRenderFrameRates(0f, Math.max(minRefreshRate, peakRefreshRate));
- mVotesStorage.updateGlobalVote(Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE,
+ mVotesStorage.updateVote(displayId, Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE,
peakVote);
- mVotesStorage.updateGlobalVote(Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE,
+ mVotesStorage.updateVote(displayId, Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE,
Vote.forRenderFrameRates(minRefreshRate, Float.POSITIVE_INFINITY));
Vote defaultVote =
defaultRefreshRate == 0f
@@ -1498,7 +1518,8 @@
}
}
- private final class DisplayObserver implements DisplayManager.DisplayListener {
+ @VisibleForTesting
+ public final class DisplayObserver implements DisplayManager.DisplayListener {
// Note that we can never call into DisplayManager or any of the non-POD classes it
// returns, while holding mLock since it may call into DMS, which might be simultaneously
// calling into us already holding its own lock.
@@ -1590,6 +1611,7 @@
updateDisplayModes(displayId, displayInfo);
updateLayoutLimitedFrameRate(displayId, displayInfo);
updateUserSettingDisplayPreferredSize(displayInfo);
+ mSettingsObserver.updateRefreshRateSettingLocked(displayId);
}
@Nullable
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index fe91050..d0c0543 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -1249,6 +1249,21 @@
}
}
}
+ // Remove uninstalled components from user-set list
+ final ArraySet<String> userSet = mUserSetServices.get(uninstalledUserId);
+ if (userSet != null) {
+ int numServices = userSet.size();
+ for (int i = numServices - 1; i >= 0; i--) {
+ String pkgOrComponent = userSet.valueAt(i);
+ if (TextUtils.equals(pkg, getPackageName(pkgOrComponent))) {
+ userSet.removeAt(i);
+ if (DEBUG) {
+ Slog.v(TAG, "Removing " + pkgOrComponent
+ + " from user-set list; uninstalled");
+ }
+ }
+ }
+ }
}
return removed;
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index c2a1b6b..c2b5964 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -184,6 +184,7 @@
import android.companion.ICompanionDeviceManager;
import android.compat.annotation.ChangeId;
import android.compat.annotation.EnabledAfter;
+import android.compat.annotation.EnabledSince;
import android.compat.annotation.LoggingOnly;
import android.content.AttributionSource;
import android.content.BroadcastReceiver;
@@ -555,7 +556,7 @@
* creation and activation of an implicit {@link android.app.AutomaticZenRule}.
*/
@ChangeId
- @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM)
+ @EnabledSince(targetSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM)
static final long MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES = 308670109L;
private static final Duration POST_WAKE_LOCK_TIMEOUT = Duration.ofSeconds(30);
@@ -828,6 +829,22 @@
}
}
+ // Removes all notifications with the specified user & package.
+ public void removePackageNotifications(String pkg, @UserIdInt int userId) {
+ synchronized (mBufferLock) {
+ Iterator<Pair<StatusBarNotification, Integer>> bufferIter = descendingIterator();
+ while (bufferIter.hasNext()) {
+ final Pair<StatusBarNotification, Integer> pair = bufferIter.next();
+ if (pair.first != null
+ && userId == pair.first.getNormalizedUserId()
+ && pkg != null && pkg.equals(pair.first.getPackageName())
+ && pair.first.getNotification() != null) {
+ bufferIter.remove();
+ }
+ }
+ }
+ }
+
void dumpImpl(PrintWriter pw, @NonNull DumpFilter filter) {
synchronized (mBufferLock) {
Iterator<Pair<StatusBarNotification, Integer>> iter = descendingIterator();
@@ -1902,7 +1919,6 @@
unhideNotificationsForPackages(pkgList, uidList);
}
}
-
mHandler.scheduleOnPackageChanged(removingPackage, changeUserId, pkgList, uidList);
}
}
@@ -4216,7 +4232,8 @@
boolean previouslyExisted = mPreferencesHelper.deleteNotificationChannel(
pkg, callingUid, channelId, callingUid, isSystemOrSystemUi);
if (previouslyExisted) {
- // Remove from both recent notification archive and notification history
+ // Remove from both recent notification archive (recently dismissed notifications)
+ // and notification history
mArchive.removeChannelNotifications(pkg, callingUser, channelId);
mHistoryManager.deleteNotificationChannel(pkg, callingUid, channelId);
mListeners.notifyNotificationChannelChanged(pkg,
@@ -9418,7 +9435,11 @@
for (int i = 0; i < size; i++) {
final String pkg = pkgList[i];
final int uid = uidList[i];
- mHistoryManager.onPackageRemoved(UserHandle.getUserId(uid), pkg);
+ final int userHandle = UserHandle.getUserId(uid);
+ // Removes this package's notifications from both recent notification archive
+ // (recently dismissed notifications) and notification history.
+ mArchive.removePackageNotifications(pkg, userHandle);
+ mHistoryManager.onPackageRemoved(userHandle, pkg);
}
}
if (preferencesChanged) {
diff --git a/services/core/java/com/android/server/pm/PackageArchiver.java b/services/core/java/com/android/server/pm/PackageArchiver.java
index d2a4c27..968be5c 100644
--- a/services/core/java/com/android/server/pm/PackageArchiver.java
+++ b/services/core/java/com/android/server/pm/PackageArchiver.java
@@ -95,6 +95,9 @@
private static final String TAG = "PackageArchiverService";
+ public static final String EXTRA_UNARCHIVE_INTENT_SENDER =
+ "android.content.pm.extra.UNARCHIVE_INTENT_SENDER";
+
/**
* The maximum time granted for an app store to start a foreground service when unarchival
* is requested.
@@ -104,6 +107,8 @@
private static final String ARCHIVE_ICONS_DIR = "package_archiver";
+ private static final String ACTION_UNARCHIVE_DIALOG = "android.intent.action.UNARCHIVE_DIALOG";
+
private final Context mContext;
private final PackageManagerService mPm;
@@ -403,11 +408,12 @@
}
snapshot.enforceCrossUserPermission(binderUid, userId, true, true,
"unarchiveApp");
- verifyInstallPermissions();
PackageStateInternal ps;
+ PackageStateInternal callerPs;
try {
ps = getPackageState(packageName, snapshot, binderUid, userId);
+ callerPs = getPackageState(callerPackageName, snapshot, binderUid, userId);
verifyArchived(ps, userId);
} catch (PackageManager.NameNotFoundException e) {
throw new ParcelableException(e);
@@ -420,12 +426,32 @@
packageName)));
}
- // TODO(b/305902395) Introduce a confirmation dialog if the requestor only holds
- // REQUEST_INSTALL permission.
+ boolean hasInstallPackages = mContext.checkCallingOrSelfPermission(
+ Manifest.permission.INSTALL_PACKAGES)
+ == PackageManager.PERMISSION_GRANTED;
+ // We don't check the AppOpsManager here for REQUEST_INSTALL_PACKAGES because the requester
+ // is not the source of the installation.
+ boolean hasRequestInstallPackages = callerPs.getAndroidPackage().getRequestedPermissions()
+ .contains(android.Manifest.permission.REQUEST_INSTALL_PACKAGES);
+ if (!hasInstallPackages && !hasRequestInstallPackages) {
+ throw new SecurityException("You need the com.android.permission.INSTALL_PACKAGES "
+ + "or com.android.permission.REQUEST_INSTALL_PACKAGES permission to request "
+ + "an unarchival.");
+ }
+
+ if (!hasInstallPackages) {
+ requestUnarchiveConfirmation(packageName, statusReceiver);
+ return;
+ }
+
+ // TODO(b/311709794) Check that the responsible installer has INSTALL_PACKAGES or
+ // OPSTR_REQUEST_INSTALL_PACKAGES too. Edge case: In reality this should always be the case,
+ // unless a user has disabled the permission after archiving an app.
+
int draftSessionId;
try {
- draftSessionId = createDraftSession(packageName, installerPackage, statusReceiver,
- userId);
+ draftSessionId = Binder.withCleanCallingIdentity(() ->
+ createDraftSession(packageName, installerPackage, statusReceiver, userId));
} catch (RuntimeException e) {
if (e.getCause() instanceof IOException) {
throw ExceptionUtils.wrap((IOException) e.getCause());
@@ -438,15 +464,17 @@
() -> unarchiveInternal(packageName, userHandle, installerPackage, draftSessionId));
}
- private void verifyInstallPermissions() {
- if (mContext.checkCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES)
- != PackageManager.PERMISSION_GRANTED && mContext.checkCallingOrSelfPermission(
- Manifest.permission.REQUEST_INSTALL_PACKAGES)
- != PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException("You need the com.android.permission.INSTALL_PACKAGES "
- + "or com.android.permission.REQUEST_INSTALL_PACKAGES permission to request "
- + "an unarchival.");
- }
+ private void requestUnarchiveConfirmation(String packageName, IntentSender statusReceiver) {
+ final Intent dialogIntent = new Intent(ACTION_UNARCHIVE_DIALOG);
+ dialogIntent.putExtra(EXTRA_UNARCHIVE_INTENT_SENDER, statusReceiver);
+ dialogIntent.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, packageName);
+
+ final Intent broadcastIntent = new Intent();
+ broadcastIntent.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, packageName);
+ broadcastIntent.putExtra(PackageInstaller.EXTRA_UNARCHIVE_STATUS,
+ PackageInstaller.STATUS_PENDING_USER_ACTION);
+ broadcastIntent.putExtra(Intent.EXTRA_INTENT, dialogIntent);
+ sendIntent(statusReceiver, packageName, /* message= */ "", broadcastIntent);
}
private void verifyUninstallPermissions() {
@@ -461,7 +489,7 @@
}
private int createDraftSession(String packageName, String installerPackage,
- IntentSender statusReceiver, int userId) {
+ IntentSender statusReceiver, int userId) throws IOException {
PackageInstaller.SessionParams sessionParams = new PackageInstaller.SessionParams(
PackageInstaller.SessionParams.MODE_FULL_INSTALL);
sessionParams.setAppPackageName(packageName);
@@ -477,12 +505,11 @@
return existingSessionId;
}
- int sessionId = Binder.withCleanCallingIdentity(
- () -> mPm.mInstallerService.createSessionInternal(
- sessionParams,
- installerPackage, mContext.getAttributionTag(),
- installerUid,
- userId));
+ int sessionId = mPm.mInstallerService.createSessionInternal(
+ sessionParams,
+ installerPackage, mContext.getAttributionTag(),
+ installerUid,
+ userId);
// TODO(b/297358628) Also cleanup sessions upon device restart.
mPm.mHandler.postDelayed(() -> mPm.mInstallerService.cleanupDraftIfUnclaimed(sessionId),
getUnarchiveForegroundTimeout());
@@ -692,20 +719,25 @@
String message) {
Slog.d(TAG, TextUtils.formatSimple("Failed to archive %s with message %s", packageName,
message));
- final Intent fillIn = new Intent();
- fillIn.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, packageName);
- fillIn.putExtra(PackageInstaller.EXTRA_STATUS, PackageInstaller.STATUS_FAILURE);
- fillIn.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE, message);
+ final Intent intent = new Intent();
+ intent.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, packageName);
+ intent.putExtra(PackageInstaller.EXTRA_STATUS, PackageInstaller.STATUS_FAILURE);
+ intent.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE, message);
+ sendIntent(statusReceiver, packageName, message, intent);
+ }
+
+ private void sendIntent(IntentSender statusReceiver, String packageName, String message,
+ Intent intent) {
try {
final BroadcastOptions options = BroadcastOptions.makeBasic();
options.setPendingIntentBackgroundActivityStartMode(
MODE_BACKGROUND_ACTIVITY_START_DENIED);
- statusReceiver.sendIntent(mContext, 0, fillIn, /* onFinished= */ null,
+ statusReceiver.sendIntent(mContext, 0, intent, /* onFinished= */ null,
/* handler= */ null, /* requiredPermission= */ null, options.toBundle());
} catch (IntentSender.SendIntentException e) {
Slog.e(
TAG,
- TextUtils.formatSimple("Failed to send failure status for %s with message %s",
+ TextUtils.formatSimple("Failed to send status for %s with message %s",
packageName, message),
e);
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index f992bd8..fc66203 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -4693,7 +4693,7 @@
try {
mInterface.getPackageInstaller().requestUnarchive(packageName,
- /* callerPackageName= */ "", receiver.getIntentSender(),
+ mContext.getPackageName(), receiver.getIntentSender(),
new UserHandle(translatedUserId));
} catch (Exception e) {
pw.println("Failure [" + e.getMessage() + "]");
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 1cf82bd..986735f 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -202,6 +202,7 @@
import com.android.internal.accessibility.util.AccessibilityUtils;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.AssistUtils;
+import com.android.internal.display.BrightnessUtils;
import com.android.internal.inputmethod.SoftInputShowHideReason;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto;
@@ -221,7 +222,6 @@
import com.android.server.LocalServices;
import com.android.server.SystemServiceManager;
import com.android.server.UiThread;
-import com.android.server.display.BrightnessUtils;
import com.android.server.input.InputManagerInternal;
import com.android.server.input.KeyboardMetricsCollector;
import com.android.server.input.KeyboardMetricsCollector.KeyboardLogEvent;
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index f8078d2..e088d9a 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -284,7 +284,6 @@
+ " needsUpdate=" + needsUpdate);
}
- int notifyColorsWhich = 0;
synchronized (mLock) {
notifyCallbacksLocked(wallpaper);
@@ -338,7 +337,6 @@
// If this was the system wallpaper, rebind...
bindWallpaperComponentLocked(mImageWallpaper, true, false, wallpaper,
callback);
- notifyColorsWhich |= wallpaper.mWhich;
}
if (lockWallpaperChanged) {
@@ -358,7 +356,6 @@
bindWallpaperComponentLocked(mImageWallpaper, true /* force */,
false /* fromUser */, wallpaper, callback);
- notifyColorsWhich |= FLAG_LOCK;
} else if (isAppliedToLock) {
// This is system-plus-lock: we need to wipe the lock bookkeeping since
// we're falling back to displaying the system wallpaper there.
@@ -372,7 +369,6 @@
}
clearWallpaperBitmaps(mWallpaper.userId, FLAG_LOCK);
mLockWallpaperMap.remove(wallpaper.userId);
- notifyColorsWhich |= FLAG_LOCK;
}
saveSettingsLocked(wallpaper.userId);
@@ -382,9 +378,7 @@
}
// Outside of the lock since it will synchronize itself
- if (notifyColorsWhich != 0) {
- notifyWallpaperColorsChanged(wallpaper, notifyColorsWhich);
- }
+ notifyWallpaperColorsChanged(wallpaper);
}
@Override
@@ -406,16 +400,13 @@
}
}
- void notifyWallpaperColorsChanged(@NonNull WallpaperData wallpaper, int which) {
+ void notifyWallpaperColorsChanged(@NonNull WallpaperData wallpaper) {
if (DEBUG) {
Slog.i(TAG, "Notifying wallpaper colors changed");
}
if (wallpaper.connection != null) {
- wallpaper.connection.forEachDisplayConnector(connector -> {
- notifyWallpaperColorsChangedOnDisplay(wallpaper, which, connector.mDisplayId);
- });
- } else { // Lock wallpaper does not have WallpaperConnection.
- notifyWallpaperColorsChangedOnDisplay(wallpaper, which, DEFAULT_DISPLAY);
+ wallpaper.connection.forEachDisplayConnector(connector ->
+ notifyWallpaperColorsChangedOnDisplay(wallpaper, connector.mDisplayId));
}
}
@@ -430,7 +421,7 @@
return listeners;
}
- private void notifyWallpaperColorsChangedOnDisplay(@NonNull WallpaperData wallpaper, int which,
+ private void notifyWallpaperColorsChangedOnDisplay(@NonNull WallpaperData wallpaper,
int displayId) {
boolean needsExtraction;
synchronized (mLock) {
@@ -445,17 +436,20 @@
}
if (DEBUG) {
- Slog.v(TAG, "notifyWallpaperColorsChangedOnDisplay " + which);
+ Slog.v(TAG, "notifyWallpaperColorsChangedOnDisplay " + wallpaper.mWhich);
}
needsExtraction = wallpaper.primaryColors == null || wallpaper.mIsColorExtractedFromDim;
}
+ boolean notify = true;
if (needsExtraction) {
- extractColors(wallpaper);
+ notify = extractColors(wallpaper);
}
- notifyColorListeners(getAdjustedWallpaperColorsOnDimming(wallpaper), which,
- wallpaper.userId, displayId);
+ if (notify) {
+ notifyColorListeners(getAdjustedWallpaperColorsOnDimming(wallpaper),
+ wallpaper.mWhich, wallpaper.userId, displayId);
+ }
}
private static <T extends IInterface> boolean emptyCallbackList(RemoteCallbackList<T> list) {
@@ -505,8 +499,9 @@
* In this case, using the crop is more than enough. Live wallpapers are just ignored.
*
* @param wallpaper a wallpaper representation
+ * @return true unless the wallpaper changed during the color computation
*/
- private void extractColors(WallpaperData wallpaper) {
+ private boolean extractColors(WallpaperData wallpaper) {
String cropFile = null;
boolean defaultImageWallpaper = false;
int wallpaperId;
@@ -518,13 +513,13 @@
if (wallpaper.equals(mFallbackWallpaper)) {
synchronized (mLock) {
- if (mFallbackWallpaper.primaryColors != null) return;
+ if (mFallbackWallpaper.primaryColors != null) return true;
}
final WallpaperColors colors = extractDefaultImageWallpaperColors(wallpaper);
synchronized (mLock) {
mFallbackWallpaper.primaryColors = colors;
}
- return;
+ return true;
}
synchronized (mLock) {
@@ -554,7 +549,7 @@
if (colors == null) {
Slog.w(TAG, "Cannot extract colors because wallpaper could not be read.");
- return;
+ return true;
}
synchronized (mLock) {
@@ -563,8 +558,10 @@
// Now that we have the colors, let's save them into the xml
// to avoid having to run this again.
saveSettingsLocked(wallpaper.userId);
+ return true;
} else {
Slog.w(TAG, "Not setting primary colors since wallpaper changed");
+ return false;
}
}
}
@@ -1138,19 +1135,15 @@
*/
@Override
public void onWallpaperColorsChanged(WallpaperColors primaryColors, int displayId) {
- int which;
synchronized (mLock) {
// Do not broadcast changes on ImageWallpaper since it's handled
// internally by this class.
if (mImageWallpaper.equals(mWallpaper.wallpaperComponent)) {
return;
}
- which = mWallpaper.mWhich;
mWallpaper.primaryColors = primaryColors;
}
- if (which != 0) {
- notifyWallpaperColorsChangedOnDisplay(mWallpaper, which, displayId);
- }
+ notifyWallpaperColorsChangedOnDisplay(mWallpaper, displayId);
}
@Override
@@ -1794,9 +1787,9 @@
// Offload color extraction to another thread since switchUser will be called
// from the main thread.
FgThread.getHandler().post(() -> {
- notifyWallpaperColorsChanged(systemWallpaper, FLAG_SYSTEM);
- notifyWallpaperColorsChanged(lockWallpaper, FLAG_LOCK);
- notifyWallpaperColorsChanged(mFallbackWallpaper, FLAG_SYSTEM);
+ notifyWallpaperColorsChanged(systemWallpaper);
+ if (lockWallpaper != systemWallpaper) notifyWallpaperColorsChanged(lockWallpaper);
+ notifyWallpaperColorsChanged(mFallbackWallpaper);
});
} finally {
t.traceEnd();
@@ -1873,12 +1866,6 @@
data = mWallpaperMap.get(userId);
}
}
-
- // When clearing a wallpaper, broadcast new valid colors
- if (data != null) {
- notifyWallpaperColorsChanged(data, which);
- notifyWallpaperColorsChanged(mFallbackWallpaper, FLAG_SYSTEM);
- }
}
private void clearWallpaperLocked(int which, int userId, boolean fromForeground,
@@ -2650,7 +2637,7 @@
}
}
for (WallpaperData wp: pendingColorExtraction) {
- notifyWallpaperColorsChanged(wp, wp.mWhich);
+ notifyWallpaperColorsChanged(wp);
}
} finally {
Binder.restoreCallingIdentity(ident);
@@ -3030,8 +3017,7 @@
}
if (shouldNotifyColors) {
- notifyWallpaperColorsChanged(newWallpaper, which);
- notifyWallpaperColorsChanged(mFallbackWallpaper, FLAG_SYSTEM);
+ notifyWallpaperColorsChanged(newWallpaper);
}
return bindSuccess;
}
diff --git a/services/core/java/com/android/server/wm/ActivityClientController.java b/services/core/java/com/android/server/wm/ActivityClientController.java
index faccca8..315e7d8 100644
--- a/services/core/java/com/android/server/wm/ActivityClientController.java
+++ b/services/core/java/com/android/server/wm/ActivityClientController.java
@@ -55,6 +55,7 @@
import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_NONE;
import static com.android.server.wm.ActivityTaskManagerService.TAG_SWITCH;
import static com.android.server.wm.ActivityTaskManagerService.enforceNotIsolatedCaller;
+import static com.android.window.flags.Flags.allowDisableActivityRecordInputSink;
import android.Manifest;
import android.annotation.ColorInt;
@@ -1688,4 +1689,20 @@
return r.mRequestedLaunchingTaskFragmentToken == taskFragmentToken;
}
}
+
+ @Override
+ public void setActivityRecordInputSinkEnabled(IBinder activityToken, boolean enabled) {
+ if (!allowDisableActivityRecordInputSink()) {
+ return;
+ }
+
+ mService.mAmInternal.enforceCallingPermission(
+ Manifest.permission.INTERNAL_SYSTEM_WINDOW, "setActivityRecordInputSinkEnabled");
+ synchronized (mGlobalLock) {
+ final ActivityRecord r = ActivityRecord.forTokenLocked(activityToken);
+ if (r != null) {
+ r.mActivityRecordInputSinkEnabled = enabled;
+ }
+ }
+ }
}
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 081759d..d90d4ff 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -970,6 +970,8 @@
boolean mWaitForEnteringPinnedMode;
final ActivityRecordInputSink mActivityRecordInputSink;
+ // System activities with INTERNAL_SYSTEM_WINDOW can disable ActivityRecordInputSink.
+ boolean mActivityRecordInputSinkEnabled = true;
// Activities with this uid are allowed to not create an input sink while being in the same
// task and directly above this ActivityRecord. This field is updated whenever a new activity
diff --git a/services/core/java/com/android/server/wm/ActivityRecordInputSink.java b/services/core/java/com/android/server/wm/ActivityRecordInputSink.java
index be7d9b6..c61d863 100644
--- a/services/core/java/com/android/server/wm/ActivityRecordInputSink.java
+++ b/services/core/java/com/android/server/wm/ActivityRecordInputSink.java
@@ -86,7 +86,8 @@
final boolean allowPassthrough = activityBelowInTask != null && (
activityBelowInTask.mAllowedTouchUid == mActivityRecord.getUid()
|| activityBelowInTask.isUid(mActivityRecord.getUid()));
- if (allowPassthrough || !mIsCompatEnabled || mActivityRecord.isInTransition()) {
+ if (allowPassthrough || !mIsCompatEnabled || mActivityRecord.isInTransition()
+ || !mActivityRecord.mActivityRecordInputSinkEnabled) {
mInputWindowHandleWrapper.setInputConfigMasked(InputConfig.NOT_TOUCHABLE,
InputConfig.NOT_TOUCHABLE);
} else {
diff --git a/services/core/java/com/android/server/wm/ClientLifecycleManager.java b/services/core/java/com/android/server/wm/ClientLifecycleManager.java
index 28f656e..8b282dd3 100644
--- a/services/core/java/com/android/server/wm/ClientLifecycleManager.java
+++ b/services/core/java/com/android/server/wm/ClientLifecycleManager.java
@@ -58,6 +58,23 @@
}
/**
+ * Similar to {@link #scheduleTransactionItem}, but is called without WM lock.
+ *
+ * @see WindowProcessController#setReportedProcState(int)
+ */
+ void scheduleTransactionItemUnlocked(@NonNull IApplicationThread client,
+ @NonNull ClientTransactionItem transactionItem) throws RemoteException {
+ // Immediately dispatching to client, and must not access WMS.
+ final ClientTransaction clientTransaction = ClientTransaction.obtain(client);
+ if (transactionItem.isActivityLifecycleItem()) {
+ clientTransaction.setLifecycleStateRequest((ActivityLifecycleItem) transactionItem);
+ } else {
+ clientTransaction.addCallback(transactionItem);
+ }
+ scheduleTransaction(clientTransaction);
+ }
+
+ /**
* Schedules a single transaction item, either a callback or a lifecycle request, delivery to
* client application.
* @throws RemoteException
@@ -65,6 +82,7 @@
*/
void scheduleTransactionItem(@NonNull IApplicationThread client,
@NonNull ClientTransactionItem transactionItem) throws RemoteException {
+ // TODO(b/260873529): queue the transaction items.
final ClientTransaction clientTransaction = ClientTransaction.obtain(client);
if (transactionItem.isActivityLifecycleItem()) {
clientTransaction.setLifecycleStateRequest((ActivityLifecycleItem) transactionItem);
@@ -82,6 +100,7 @@
void scheduleTransactionAndLifecycleItems(@NonNull IApplicationThread client,
@NonNull ClientTransactionItem transactionItem,
@NonNull ActivityLifecycleItem lifecycleItem) throws RemoteException {
+ // TODO(b/260873529): replace with #scheduleTransactionItem after launch for cleanup.
final ClientTransaction clientTransaction = ClientTransaction.obtain(client);
clientTransaction.addCallback(transactionItem);
clientTransaction.setLifecycleStateRequest(lifecycleItem);
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index 558bf9d..2b18f07 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -388,13 +388,22 @@
final IApplicationThread thread = mThread;
if (prevProcState >= CACHED_CONFIG_PROC_STATE && repProcState < CACHED_CONFIG_PROC_STATE
&& thread != null && mHasCachedConfiguration) {
- final Configuration config;
+ final ConfigurationChangeItem configurationChangeItem;
synchronized (mLastReportedConfiguration) {
- config = new Configuration(mLastReportedConfiguration);
+ onConfigurationChangePreScheduled(mLastReportedConfiguration);
+ configurationChangeItem = ConfigurationChangeItem.obtain(
+ mLastReportedConfiguration, mLastTopActivityDeviceId);
}
// Schedule immediately to make sure the app component (e.g. receiver, service) can get
// the latest configuration in their lifecycle callbacks (e.g. onReceive, onCreate).
- scheduleConfigurationChange(thread, config);
+ try {
+ // No WM lock here.
+ mAtm.getLifecycleManager().scheduleTransactionItemUnlocked(
+ thread, configurationChangeItem);
+ } catch (Exception e) {
+ Slog.e(TAG_CONFIGURATION, "Failed to schedule ConfigurationChangeItem="
+ + configurationChangeItem + " owner=" + mOwner, e);
+ }
}
}
@@ -1634,11 +1643,12 @@
}
}
- scheduleConfigurationChange(thread, config);
+ onConfigurationChangePreScheduled(config);
+ scheduleClientTransactionItem(thread, ConfigurationChangeItem.obtain(
+ config, mLastTopActivityDeviceId));
}
- private void scheduleConfigurationChange(@NonNull IApplicationThread thread,
- @NonNull Configuration config) {
+ private void onConfigurationChangePreScheduled(@NonNull Configuration config) {
ProtoLog.v(WM_DEBUG_CONFIGURATION, "Sending to proc %s new config %s", mName,
config);
if (Build.IS_DEBUGGABLE && mHasImeService) {
@@ -1646,8 +1656,6 @@
Slog.v(TAG_CONFIGURATION, "Sending to IME proc " + mName + " new config " + config);
}
mHasCachedConfiguration = false;
- scheduleClientTransactionItem(thread, ConfigurationChangeItem.obtain(
- config, mLastTopActivityDeviceId));
}
@VisibleForTesting
diff --git a/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt b/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt
index 0d196b4..7c53950 100644
--- a/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt
+++ b/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt
@@ -2175,9 +2175,9 @@
userState.appIdDevicePermissionFlags[appId]?.forEachIndexed {
_,
- deviceId,
+ persistentDeviceId,
devicePermissionFlags ->
- println("Permissions (Device $deviceId):")
+ println("Permissions (Device $persistentDeviceId):")
withIndent {
devicePermissionFlags.forEachIndexed { _, permissionName, flags ->
val isGranted = PermissionFlags.isPermissionGranted(flags)
@@ -2658,7 +2658,7 @@
override fun onDevicePermissionFlagsChanged(
appId: Int,
userId: Int,
- deviceId: String,
+ persistentDeviceId: String,
permissionName: String,
oldFlags: Int,
newFlags: Int
@@ -2681,7 +2681,8 @@
permissionName in NOTIFICATIONS_PERMISSIONS &&
runtimePermissionRevokedUids.get(uid, true)
}
- runtimePermissionChangedUidDevices.getOrPut(uid) { mutableSetOf() } += deviceId
+ runtimePermissionChangedUidDevices
+ .getOrPut(uid) { mutableSetOf() } += persistentDeviceId
}
if (permission.hasGids && !wasPermissionGranted && isPermissionGranted) {
@@ -2695,9 +2696,9 @@
isPermissionFlagsChanged = false
}
- runtimePermissionChangedUidDevices.forEachIndexed { _, uid, deviceIds ->
- deviceIds.forEach { deviceId ->
- onPermissionsChangeListeners.onPermissionsChanged(uid, deviceId)
+ runtimePermissionChangedUidDevices.forEachIndexed { _, uid, persistentDeviceIds ->
+ persistentDeviceIds.forEach { persistentDeviceId ->
+ onPermissionsChangeListeners.onPermissionsChanged(uid, persistentDeviceId)
}
}
runtimePermissionChangedUidDevices.clear()
@@ -2772,16 +2773,16 @@
when (msg.what) {
MSG_ON_PERMISSIONS_CHANGED -> {
val uid = msg.arg1
- val deviceId = msg.obj as String
- handleOnPermissionsChanged(uid, deviceId)
+ val persistentDeviceId = msg.obj as String
+ handleOnPermissionsChanged(uid, persistentDeviceId)
}
}
}
- private fun handleOnPermissionsChanged(uid: Int, deviceId: String) {
+ private fun handleOnPermissionsChanged(uid: Int, persistentDeviceId: String) {
listeners.broadcast { listener ->
try {
- listener.onPermissionsChanged(uid, deviceId)
+ listener.onPermissionsChanged(uid, persistentDeviceId)
} catch (e: RemoteException) {
Slog.e(LOG_TAG, "Error when calling OnPermissionsChangeListener", e)
}
@@ -2796,9 +2797,10 @@
listeners.unregister(listener)
}
- fun onPermissionsChanged(uid: Int, deviceId: String) {
+ fun onPermissionsChanged(uid: Int, persistentDeviceId: String) {
if (listeners.registeredCallbackCount > 0) {
- obtainMessage(MSG_ON_PERMISSIONS_CHANGED, uid, 0, deviceId).sendToTarget()
+ obtainMessage(MSG_ON_PERMISSIONS_CHANGED, uid, 0, persistentDeviceId)
+ .sendToTarget()
}
}
diff --git a/services/tests/displayservicetests/src/com/android/server/display/BrightnessSynchronizerTest.java b/services/tests/displayservicetests/src/com/android/server/display/BrightnessSynchronizerTest.java
index 2fd6e5f..06f1b27 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/BrightnessSynchronizerTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/BrightnessSynchronizerTest.java
@@ -19,6 +19,7 @@
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.isA;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -27,24 +28,29 @@
import android.content.Context;
import android.content.ContextWrapper;
import android.database.ContentObserver;
+import android.hardware.display.BrightnessInfo;
import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManager.DisplayListener;
import android.net.Uri;
import android.os.Handler;
+import android.os.PowerManager;
import android.os.UserHandle;
import android.os.test.TestLooper;
import android.provider.Settings;
import android.test.mock.MockContentResolver;
import android.view.Display;
+import android.view.DisplayAdjustments;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
import com.android.internal.display.BrightnessSynchronizer;
import com.android.internal.util.test.FakeSettingsProvider;
import com.android.server.testutils.OffsettableClock;
+import com.google.testing.junit.testparameterinjector.TestParameter;
+import com.google.testing.junit.testparameterinjector.TestParameterInjector;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -54,11 +60,12 @@
import org.mockito.MockitoAnnotations;
@SmallTest
-@RunWith(AndroidJUnit4.class)
+@RunWith(TestParameterInjector.class)
public class BrightnessSynchronizerTest {
private static final float EPSILON = 0.00001f;
private static final Uri BRIGHTNESS_URI =
Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS);
+ private static final float BRIGHTNESS_MAX = 0.6f;
private Context mContext;
private MockContentResolver mContentResolverSpy;
@@ -66,15 +73,29 @@
private DisplayListener mDisplayListener;
private ContentObserver mContentObserver;
private TestLooper mTestLooper;
+ private BrightnessSynchronizer mSynchronizer;
@Mock private DisplayManager mDisplayManagerMock;
@Captor private ArgumentCaptor<DisplayListener> mDisplayListenerCaptor;
@Captor private ArgumentCaptor<ContentObserver> mContentObserverCaptor;
+ // Feature flag that will eventually be removed
+ @TestParameter private boolean mIntRangeUserPerceptionEnabled;
+
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
- mContext = spy(new ContextWrapper(ApplicationProvider.getApplicationContext()));
+
+ Display display = mock(Display.class);
+ when(display.getDisplayAdjustments()).thenReturn(new DisplayAdjustments());
+ BrightnessInfo info = new BrightnessInfo(PowerManager.BRIGHTNESS_INVALID_FLOAT,
+ PowerManager.BRIGHTNESS_MIN, BRIGHTNESS_MAX,
+ BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF, BRIGHTNESS_MAX,
+ BrightnessInfo.BRIGHTNESS_MAX_REASON_NONE);
+ when(display.getBrightnessInfo()).thenReturn(info);
+
+ mContext = spy(new ContextWrapper(
+ ApplicationProvider.getApplicationContext().createDisplayContext(display)));
mContentResolverSpy = spy(new MockContentResolver(mContext));
mContentResolverSpy.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
when(mContext.getContentResolver()).thenReturn(mContentResolverSpy);
@@ -128,13 +149,12 @@
@Test
public void testSetSameIntValue_nothingUpdated() {
putFloatSetting(0.5f);
- putIntSetting(128);
start();
- putIntSetting(128);
+ putIntSetting(fToI(0.5f));
advanceTime(10);
verify(mDisplayManagerMock, times(0)).setBrightness(
- eq(Display.DEFAULT_DISPLAY), eq(iToF(128)));
+ eq(Display.DEFAULT_DISPLAY), eq(0.5f));
}
@Test
@@ -154,14 +174,13 @@
// Verify that this update did not get sent to float, because synchronizer
// is still waiting for confirmation of its first value.
verify(mDisplayManagerMock, times(0)).setBrightness(
- eq(Display.DEFAULT_DISPLAY), eq(iToF(20)));
+ Display.DEFAULT_DISPLAY, iToF(20));
// Send the confirmation of the initial change. This should trigger the new value to
// finally be processed and we can verify that the new value (20) is sent.
putIntSetting(fToI(0.4f));
advanceTime(10);
- verify(mDisplayManagerMock).setBrightness(
- eq(Display.DEFAULT_DISPLAY), eq(iToF(20)));
+ verify(mDisplayManagerMock).setBrightness(Display.DEFAULT_DISPLAY, iToF(20));
}
@@ -183,8 +202,7 @@
advanceTime(200);
// Verify that the new value gets sent because the timeout expired.
- verify(mDisplayManagerMock).setBrightness(
- eq(Display.DEFAULT_DISPLAY), eq(iToF(20)));
+ verify(mDisplayManagerMock).setBrightness(Display.DEFAULT_DISPLAY, iToF(20));
// Send a confirmation of the initial event, BrightnessSynchronizer should treat this as a
// new event because the timeout had already expired
@@ -196,14 +214,14 @@
// Verify we sent what would have been the confirmation as a new event to displaymanager.
// We do both fToI and iToF because the conversions are not symmetric.
- verify(mDisplayManagerMock).setBrightness(
- eq(Display.DEFAULT_DISPLAY), eq(iToF(fToI(0.4f))));
+ verify(mDisplayManagerMock).setBrightness(Display.DEFAULT_DISPLAY,
+ iToF(fToI(0.4f)));
}
- private BrightnessSynchronizer start() {
- BrightnessSynchronizer bs = new BrightnessSynchronizer(mContext, mTestLooper.getLooper(),
- mClock::now);
- bs.startSynchronizing();
+ private void start() {
+ mSynchronizer = new BrightnessSynchronizer(mContext, mTestLooper.getLooper(), mClock::now,
+ mIntRangeUserPerceptionEnabled);
+ mSynchronizer.startSynchronizing();
verify(mDisplayManagerMock).registerDisplayListener(mDisplayListenerCaptor.capture(),
isA(Handler.class), eq(DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS));
mDisplayListener = mDisplayListenerCaptor.getValue();
@@ -211,7 +229,6 @@
verify(mContentResolverSpy).registerContentObserver(eq(BRIGHTNESS_URI), eq(false),
mContentObserverCaptor.capture(), eq(UserHandle.USER_ALL));
mContentObserver = mContentObserverCaptor.getValue();
- return bs;
}
private int getIntSetting() throws Exception {
@@ -241,11 +258,19 @@
}
private int fToI(float brightness) {
- return BrightnessSynchronizer.brightnessFloatToInt(brightness);
+ if (mIntRangeUserPerceptionEnabled) {
+ return BrightnessSynchronizer.brightnessFloatToIntSetting(mContext, brightness);
+ } else {
+ return BrightnessSynchronizer.brightnessFloatToInt(brightness);
+ }
}
private float iToF(int brightness) {
- return BrightnessSynchronizer.brightnessIntToFloat(brightness);
+ if (mIntRangeUserPerceptionEnabled) {
+ return BrightnessSynchronizer.brightnessIntSettingToFloat(mContext, brightness);
+ } else {
+ return BrightnessSynchronizer.brightnessIntToFloat(brightness);
+ }
}
private void advanceTime(long timeMs) {
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
index 353a7bb..55f56e9 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
@@ -77,6 +77,7 @@
import android.hardware.Sensor;
import android.hardware.SensorManager;
import android.hardware.display.BrightnessConfiguration;
+import android.hardware.display.BrightnessInfo;
import android.hardware.display.Curve;
import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManagerGlobal;
@@ -103,6 +104,7 @@
import android.platform.test.flag.junit.SetFlagsRule;
import android.view.ContentRecordingSession;
import android.view.Display;
+import android.view.DisplayAdjustments;
import android.view.DisplayCutout;
import android.view.DisplayEventReceiver;
import android.view.DisplayInfo;
@@ -110,7 +112,6 @@
import android.view.SurfaceControl;
import android.window.DisplayWindowPolicyController;
-import androidx.test.InstrumentationRegistry;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
@@ -358,7 +359,11 @@
LocalServices.removeServiceForTest(PackageManagerInternal.class);
LocalServices.addService(PackageManagerInternal.class, mMockPackageManagerInternal);
// TODO: b/287945043
- mContext = spy(new ContextWrapper(ApplicationProvider.getApplicationContext()));
+ Display display = mock(Display.class);
+ when(display.getDisplayAdjustments()).thenReturn(new DisplayAdjustments());
+ when(display.getBrightnessInfo()).thenReturn(mock(BrightnessInfo.class));
+ mContext = spy(new ContextWrapper(
+ ApplicationProvider.getApplicationContext().createDisplayContext(display)));
mResources = Mockito.spy(mContext.getResources());
manageDisplaysPermission(/* granted= */ false);
when(mContext.getResources()).thenReturn(mResources);
@@ -2163,7 +2168,6 @@
@Test
public void testSettingTwoBrightnessConfigurationsOnMultiDisplay() {
- Context mContext = InstrumentationRegistry.getInstrumentation().getContext();
DisplayManager displayManager = mContext.getSystemService(DisplayManager.class);
// get the first two internal displays
diff --git a/services/tests/displayservicetests/src/com/android/server/display/RefreshRateSettingsUtilsTest.java b/services/tests/displayservicetests/src/com/android/server/display/RefreshRateSettingsUtilsTest.java
index 5c50acb..b7cbac5 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/RefreshRateSettingsUtilsTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/RefreshRateSettingsUtilsTest.java
@@ -72,14 +72,27 @@
@Test
public void testFindHighestRefreshRateForDefaultDisplay() {
+ when(mDisplayManagerMock.getDisplay(Display.DEFAULT_DISPLAY)).thenReturn(mDisplayMock);
+ assertEquals(120,
+ RefreshRateSettingsUtils.findHighestRefreshRateForDefaultDisplay(mContext),
+ /* delta= */ 0);
+ }
+
+ @Test
+ public void testFindHighestRefreshRate() {
+ int displayId = 13;
+ when(mDisplayManagerMock.getDisplay(displayId)).thenReturn(mDisplayMock);
+ assertEquals(120,
+ RefreshRateSettingsUtils.findHighestRefreshRate(mContext, displayId),
+ /* delta= */ 0);
+ }
+
+ @Test
+ public void testFindHighestRefreshRate_DisplayIsNull() {
when(mDisplayManagerMock.getDisplay(Display.DEFAULT_DISPLAY)).thenReturn(null);
assertEquals(DEFAULT_REFRESH_RATE,
RefreshRateSettingsUtils.findHighestRefreshRateForDefaultDisplay(mContext),
/* delta= */ 0);
- when(mDisplayManagerMock.getDisplay(Display.DEFAULT_DISPLAY)).thenReturn(mDisplayMock);
- assertEquals(120,
- RefreshRateSettingsUtils.findHighestRefreshRateForDefaultDisplay(mContext),
- /* delta= */ 0);
}
}
diff --git a/services/tests/displayservicetests/src/com/android/server/display/mode/DisplayModeDirectorTest.java b/services/tests/displayservicetests/src/com/android/server/display/mode/DisplayModeDirectorTest.java
index 499e700..6798a2d 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/mode/DisplayModeDirectorTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/mode/DisplayModeDirectorTest.java
@@ -291,6 +291,7 @@
};
private static final int DISPLAY_ID = Display.DEFAULT_DISPLAY;
+ private static final int DISPLAY_ID_2 = Display.DEFAULT_DISPLAY + 1;
private static final int MODE_ID = 1;
private static final float TRANSITION_POINT = 0.763f;
@@ -1537,9 +1538,12 @@
public void testPeakRefreshRate_FlagEnabled() {
when(mDisplayManagerFlags.isBackUpSmoothDisplayAndForcePeakRefreshRateEnabled())
.thenReturn(true);
- float highestRefreshRate = 130;
- doReturn(highestRefreshRate).when(() ->
- RefreshRateSettingsUtils.findHighestRefreshRateForDefaultDisplay(mContext));
+ float highestRefreshRate1 = 130;
+ float highestRefreshRate2 = 132;
+ doReturn(highestRefreshRate1).when(() ->
+ RefreshRateSettingsUtils.findHighestRefreshRate(mContext, DISPLAY_ID));
+ doReturn(highestRefreshRate2).when(() ->
+ RefreshRateSettingsUtils.findHighestRefreshRate(mContext, DISPLAY_ID_2));
DisplayModeDirector director =
createDirectorFromRefreshRateArray(new float[] {60.f, 90.f}, 0);
director.getBrightnessObserver().setDefaultDisplayState(Display.STATE_ON);
@@ -1550,10 +1554,14 @@
setPeakRefreshRate(Float.POSITIVE_INFINITY);
- Vote vote = director.getVote(Display.DEFAULT_DISPLAY,
+ Vote vote1 = director.getVote(DISPLAY_ID,
Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE);
- assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ 0, /* frameRateHigh= */
- highestRefreshRate);
+ Vote vote2 = director.getVote(DISPLAY_ID_2,
+ Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE);
+ assertVoteForRenderFrameRateRange(vote1, /* frameRateLow= */ 0,
+ /* frameRateHigh= */ highestRefreshRate1);
+ assertVoteForRenderFrameRateRange(vote2, /* frameRateLow= */ 0,
+ /* frameRateHigh= */ highestRefreshRate2);
}
@Test
@@ -1571,19 +1579,54 @@
setPeakRefreshRate(peakRefreshRate);
- Vote vote = director.getVote(Display.DEFAULT_DISPLAY,
+ Vote vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE);
+ assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ 0,
+ /* frameRateHigh= */ peakRefreshRate);
+ }
+
+ @Test
+ public void testPeakRefreshRate_DisplayChanged() {
+ when(mDisplayManagerFlags.isBackUpSmoothDisplayAndForcePeakRefreshRateEnabled())
+ .thenReturn(true);
+ float highestRefreshRate = 130;
+ doReturn(highestRefreshRate).when(() ->
+ RefreshRateSettingsUtils.findHighestRefreshRate(mContext, DISPLAY_ID));
+ DisplayModeDirector director =
+ createDirectorFromRefreshRateArray(new float[] {60.f, 90.f}, 0);
+ director.getBrightnessObserver().setDefaultDisplayState(Display.STATE_ON);
+
+ Sensor lightSensor = createLightSensor();
+ SensorManager sensorManager = createMockSensorManager(lightSensor);
+ director.start(sensorManager);
+
+ setPeakRefreshRate(Float.POSITIVE_INFINITY);
+
+ Vote vote = director.getVote(DISPLAY_ID,
Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE);
- assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ 0, /* frameRateHigh= */
- peakRefreshRate);
+ assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ 0,
+ /* frameRateHigh= */ highestRefreshRate);
+
+ // The highest refresh rate of the display changes
+ highestRefreshRate = 140;
+ doReturn(highestRefreshRate).when(() ->
+ RefreshRateSettingsUtils.findHighestRefreshRate(mContext, DISPLAY_ID));
+ director.getDisplayObserver().onDisplayChanged(DISPLAY_ID);
+
+ vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE);
+ assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ 0,
+ /* frameRateHigh= */ highestRefreshRate);
}
@Test
public void testMinRefreshRate_FlagEnabled() {
when(mDisplayManagerFlags.isBackUpSmoothDisplayAndForcePeakRefreshRateEnabled())
.thenReturn(true);
- float highestRefreshRate = 130;
- doReturn(highestRefreshRate).when(() ->
- RefreshRateSettingsUtils.findHighestRefreshRateForDefaultDisplay(mContext));
+ float highestRefreshRate1 = 130;
+ float highestRefreshRate2 = 132;
+ doReturn(highestRefreshRate1).when(() ->
+ RefreshRateSettingsUtils.findHighestRefreshRate(mContext, DISPLAY_ID));
+ doReturn(highestRefreshRate2).when(() ->
+ RefreshRateSettingsUtils.findHighestRefreshRate(mContext, DISPLAY_ID_2));
DisplayModeDirector director =
createDirectorFromRefreshRateArray(new float[] {60.f, 90.f}, 0);
director.getBrightnessObserver().setDefaultDisplayState(Display.STATE_ON);
@@ -1594,9 +1637,12 @@
setMinRefreshRate(Float.POSITIVE_INFINITY);
- Vote vote = director.getVote(Display.DEFAULT_DISPLAY,
+ Vote vote1 = director.getVote(DISPLAY_ID, Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE);
+ Vote vote2 = director.getVote(DISPLAY_ID_2,
Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE);
- assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ highestRefreshRate,
+ assertVoteForRenderFrameRateRange(vote1, /* frameRateLow= */ highestRefreshRate1,
+ /* frameRateHigh= */ Float.POSITIVE_INFINITY);
+ assertVoteForRenderFrameRateRange(vote2, /* frameRateLow= */ highestRefreshRate2,
/* frameRateHigh= */ Float.POSITIVE_INFINITY);
}
@@ -1615,13 +1661,44 @@
setMinRefreshRate(minRefreshRate);
- Vote vote = director.getVote(Display.DEFAULT_DISPLAY,
- Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE);
+ Vote vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE);
assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ minRefreshRate,
/* frameRateHigh= */ Float.POSITIVE_INFINITY);
}
@Test
+ public void testMinRefreshRate_DisplayChanged() {
+ when(mDisplayManagerFlags.isBackUpSmoothDisplayAndForcePeakRefreshRateEnabled())
+ .thenReturn(true);
+ float highestRefreshRate = 130;
+ doReturn(highestRefreshRate).when(() ->
+ RefreshRateSettingsUtils.findHighestRefreshRate(mContext, DISPLAY_ID));
+ DisplayModeDirector director =
+ createDirectorFromRefreshRateArray(new float[] {60.f, 90.f}, 0);
+ director.getBrightnessObserver().setDefaultDisplayState(Display.STATE_ON);
+
+ Sensor lightSensor = createLightSensor();
+ SensorManager sensorManager = createMockSensorManager(lightSensor);
+ director.start(sensorManager);
+
+ setMinRefreshRate(Float.POSITIVE_INFINITY);
+
+ Vote vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE);
+ assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ highestRefreshRate,
+ /* frameRateHigh= */ Float.POSITIVE_INFINITY);
+
+ // The highest refresh rate of the display changes
+ highestRefreshRate = 140;
+ doReturn(highestRefreshRate).when(() ->
+ RefreshRateSettingsUtils.findHighestRefreshRate(mContext, DISPLAY_ID));
+ director.getDisplayObserver().onDisplayChanged(DISPLAY_ID);
+
+ vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE);
+ assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ highestRefreshRate,
+ /* frameRateHigh= */ Float.POSITIVE_INFINITY);
+ }
+
+ @Test
public void testSensorRegistration() {
// First, configure brightness zones or DMD won't register for sensor data.
final FakeDeviceConfig config = mInjector.getDeviceConfig();
@@ -3368,7 +3445,7 @@
public static class FakesInjector implements DisplayModeDirector.Injector {
private final FakeDeviceConfig mDeviceConfig;
private final DisplayInfo mDisplayInfo;
- private final Display mDisplay;
+ private final Map<Integer, Display> mDisplays;
private boolean mDisplayInfoValid = true;
private final DisplayManagerInternal mDisplayManagerInternal;
private final StatusBarManagerInternal mStatusBarManagerInternal;
@@ -3389,7 +3466,8 @@
mDisplayInfo.defaultModeId = MODE_ID;
mDisplayInfo.supportedModes = new Display.Mode[] {new Display.Mode(MODE_ID,
800, 600, /* refreshRate= */ 60)};
- mDisplay = createDisplay(DISPLAY_ID);
+ mDisplays = Map.of(DISPLAY_ID, createDisplay(DISPLAY_ID),
+ DISPLAY_ID_2, createDisplay(DISPLAY_ID_2));
mDisplayManagerInternal = displayManagerInternal;
mStatusBarManagerInternal = statusBarManagerInternal;
mSensorManagerInternal = sensorManagerInternal;
@@ -3420,12 +3498,12 @@
@Override
public Display getDisplay(int displayId) {
- return mDisplay;
+ return mDisplays.get(displayId);
}
@Override
public Display[] getDisplays() {
- return new Display[] { mDisplay };
+ return mDisplays.values().toArray(new Display[0]);
}
@Override
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/PackageArchiverTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/PackageArchiverTest.java
index 18a2acc..733a433 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/PackageArchiverTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/PackageArchiverTest.java
@@ -65,6 +65,7 @@
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.server.pm.pkg.AndroidPackage;
import com.android.server.pm.pkg.ArchiveState;
import com.android.server.pm.pkg.PackageStateInternal;
import com.android.server.pm.pkg.PackageUserStateImpl;
@@ -81,6 +82,7 @@
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
+import java.util.Set;
@SmallTest
@Presubmit
@@ -114,6 +116,8 @@
@Mock
private PackageStateInternal mPackageState;
@Mock
+ private PackageStateInternal mCallerPackageState;
+ @Mock
private Bitmap mIcon;
private final InstallSource mInstallSource =
@@ -155,6 +159,11 @@
mPackageState);
when(mComputer.getPackageStateFiltered(eq(INSTALLER_PACKAGE), anyInt(),
anyInt())).thenReturn(mock(PackageStateInternal.class));
+ when(mComputer.getPackageStateFiltered(eq(CALLER_PACKAGE), anyInt(), anyInt())).thenReturn(
+ mCallerPackageState);
+ AndroidPackage androidPackage = mock(AndroidPackage.class);
+ when(mCallerPackageState.getAndroidPackage()).thenReturn(androidPackage);
+ when(androidPackage.getRequestedPermissions()).thenReturn(Set.of());
when(mPackageState.getPackageName()).thenReturn(PACKAGE);
when(mPackageState.getInstallSource()).thenReturn(mInstallSource);
mPackageSetting = createBasicPackageSetting();
diff --git a/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperManagerServiceTests.java b/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperManagerServiceTests.java
index 3dbab13..15ae463 100644
--- a/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperManagerServiceTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperManagerServiceTests.java
@@ -453,7 +453,7 @@
doAnswer(invocation -> timestamps[0] = SystemClock.elapsedRealtime())
.when(sContext).sendBroadcastAsUser(any(), any());
doAnswer(invocation -> timestamps[1] = SystemClock.elapsedRealtime())
- .when(mService).notifyWallpaperColorsChanged(wallpaper, FLAG_SYSTEM);
+ .when(mService).notifyWallpaperColorsChanged(wallpaper);
assertNull(wallpaper.wallpaperObserver);
mService.switchUser(wallpaper.userId, null);
diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java
index d87b8d1..b5ba322 100644
--- a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java
@@ -773,6 +773,30 @@
}
@Test
+ public void getAllPersistentDeviceIds_respectsCurrentAssociations() {
+ mVdms.onCdmAssociationsChanged(List.of(mAssociationInfo));
+ TestableLooper.get(this).processAllMessages();
+
+ assertThat(mLocalService.getAllPersistentDeviceIds())
+ .containsExactly(mDeviceImpl.getPersistentDeviceId());
+
+ mVdms.onCdmAssociationsChanged(List.of(
+ createAssociationInfo(2, AssociationRequest.DEVICE_PROFILE_APP_STREAMING),
+ createAssociationInfo(3, AssociationRequest.DEVICE_PROFILE_AUTOMOTIVE_PROJECTION),
+ createAssociationInfo(4, AssociationRequest.DEVICE_PROFILE_WATCH)));
+ TestableLooper.get(this).processAllMessages();
+
+ assertThat(mLocalService.getAllPersistentDeviceIds()).containsExactly(
+ VirtualDeviceImpl.createPersistentDeviceId(2),
+ VirtualDeviceImpl.createPersistentDeviceId(3));
+
+ mVdms.onCdmAssociationsChanged(Collections.emptyList());
+ TestableLooper.get(this).processAllMessages();
+
+ assertThat(mLocalService.getAllPersistentDeviceIds()).isEmpty();
+ }
+
+ @Test
public void onAppsOnVirtualDeviceChanged_singleVirtualDevice_listenersNotified() {
ArraySet<Integer> uids = new ArraySet<>(Arrays.asList(UID_1, UID_2));
mLocalService.registerAppsOnVirtualDeviceListener(mAppsOnVirtualDeviceListener);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ArchiveTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ArchiveTest.java
index 4b6183d..8bc027d 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ArchiveTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ArchiveTest.java
@@ -31,6 +31,7 @@
import android.app.Notification;
import android.os.UserHandle;
import android.os.UserManager;
+import android.platform.test.flag.junit.SetFlagsRule;
import android.service.notification.StatusBarNotification;
import android.test.suitebuilder.annotation.SmallTest;
@@ -39,6 +40,7 @@
import com.android.server.UiServiceTestCase;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -55,6 +57,9 @@
@SmallTest
@RunWith(AndroidJUnit4.class)
public class ArchiveTest extends UiServiceTestCase {
+ @Rule
+ public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
private static final int SIZE = 5;
private NotificationManagerService.Archive mArchive;
@@ -249,4 +254,29 @@
assertThat(expected).contains(sbn.getKey());
}
}
+
+ @Test
+ public void testRemoveNotificationsByPackage() {
+ List<String> expected = new ArrayList<>();
+
+ StatusBarNotification sbn_remove = getNotification("pkg_remove", 0,
+ UserHandle.of(USER_CURRENT));
+ mArchive.record(sbn_remove, REASON_CANCEL);
+
+ StatusBarNotification sbn_keep = getNotification("pkg_keep", 1,
+ UserHandle.of(USER_CURRENT));
+ mArchive.record(sbn_keep, REASON_CANCEL);
+ expected.add(sbn_keep.getKey());
+
+ StatusBarNotification sbn_remove2 = getNotification("pkg_remove", 2,
+ UserHandle.of(USER_CURRENT));
+ mArchive.record(sbn_remove2, REASON_CANCEL);
+
+ mArchive.removePackageNotifications("pkg_remove", USER_CURRENT);
+ List<StatusBarNotification> actual = Arrays.asList(mArchive.getArray(mUm, SIZE, true));
+ assertThat(actual).hasSize(expected.size());
+ for (StatusBarNotification sbn : actual) {
+ assertThat(expected).contains(sbn.getKey());
+ }
+ }
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
index 2136811..344a4b0 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
@@ -1077,6 +1077,26 @@
}
@Test
+ public void testPackageUninstall_componentNoLongerUserSetList() throws Exception {
+ final String pkg = "this.is.a.package.name";
+ final String component = pkg + "/Ba";
+ for (int approvalLevel : new int[] { APPROVAL_BY_COMPONENT, APPROVAL_BY_PACKAGE}) {
+ ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles,
+ mIpm, approvalLevel);
+ writeExpectedValuesToSettings(approvalLevel);
+ service.migrateToXml();
+
+ final String verifyValue = (approvalLevel == APPROVAL_BY_COMPONENT) ? component : pkg;
+
+ assertThat(service.isPackageOrComponentAllowed(verifyValue, 0)).isTrue();
+ assertThat(service.isPackageOrComponentUserSet(verifyValue, 0)).isTrue();
+
+ service.onPackagesChanged(true, new String[]{pkg}, new int[]{103});
+ assertThat(service.isPackageOrComponentUserSet(verifyValue, 0)).isFalse();
+ }
+ }
+
+ @Test
public void testIsPackageAllowed() {
for (int approvalLevel : new int[] {APPROVAL_BY_COMPONENT, APPROVAL_BY_PACKAGE}) {
ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles,
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 a47fbce..b45dcd4 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -65,6 +65,7 @@
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.Build.VERSION_CODES.O_MR1;
import static android.os.Build.VERSION_CODES.P;
+import static android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE;
import static android.os.PowerManager.PARTIAL_WAKE_LOCK;
import static android.os.PowerWhitelistManager.REASON_NOTIFICATION_SERVICE;
import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
@@ -72,7 +73,6 @@
import static android.os.UserManager.USER_TYPE_FULL_SECONDARY;
import static android.os.UserManager.USER_TYPE_PROFILE_CLONE;
import static android.os.UserManager.USER_TYPE_PROFILE_MANAGED;
-import static android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE;
import static android.provider.Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
import static android.service.notification.Adjustment.KEY_IMPORTANCE;
import static android.service.notification.Adjustment.KEY_USER_SENTIMENT;
@@ -307,7 +307,6 @@
import java.util.concurrent.CountDownLatch;
import java.util.function.Consumer;
-
@SmallTest
@RunWith(AndroidTestingRunner.class)
@SuppressLint("GuardedBy") // It's ok for this test to access guarded methods from the service.
@@ -813,6 +812,20 @@
mPackageIntentReceiver.onReceive(getContext(), intent);
}
+ private void simulatePackageRemovedBroadcast(String pkg, int uid) {
+ // mimics receive broadcast that package is removed, but doesn't remove the package.
+ final Bundle extras = new Bundle();
+ extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST,
+ new String[]{pkg});
+ extras.putIntArray(Intent.EXTRA_CHANGED_UID_LIST, new int[]{uid});
+
+ final Intent intent = new Intent(Intent.ACTION_PACKAGE_REMOVED);
+ intent.setData(Uri.parse("package:" + pkg));
+ intent.putExtras(extras);
+
+ mPackageIntentReceiver.onReceive(getContext(), intent);
+ }
+
private void simulatePackageDistractionBroadcast(int flag, String[] pkgs, int[] uids) {
// mimics receive broadcast that package is (un)distracting
// but does not actually register that info with packagemanager
@@ -878,6 +891,22 @@
mTestNotificationChannel.setAllowBubbles(channelEnabled);
}
+ private void setUpPrefsForHistory(int uid, boolean globalEnabled) {
+ // Sets NOTIFICATION_HISTORY_ENABLED setting for calling process uid
+ Settings.Secure.putIntForUser(mContext.getContentResolver(),
+ Settings.Secure.NOTIFICATION_HISTORY_ENABLED, globalEnabled ? 1 : 0, uid);
+ // Sets NOTIFICATION_HISTORY_ENABLED setting for uid 0
+ Settings.Secure.putInt(mContext.getContentResolver(),
+ Settings.Secure.NOTIFICATION_HISTORY_ENABLED, globalEnabled ? 1 : 0);
+
+ // Forces an update by calling observe on mSettingsObserver, which picks up the settings
+ // changes above.
+ mService.onBootPhase(SystemService.PHASE_THIRD_PARTY_APPS_CAN_START, mMainLooper);
+
+ assertEquals(globalEnabled, Settings.Secure.getIntForUser(mContext.getContentResolver(),
+ Settings.Secure.NOTIFICATION_HISTORY_ENABLED, 0 /* =def */, uid) != 0);
+ }
+
private StatusBarNotification generateSbn(String pkg, int uid, long postTime, int userId) {
Notification.Builder nb = new Notification.Builder(mContext, "a")
.setContentTitle("foo")
@@ -9831,6 +9860,43 @@
}
@Test
+ public void testHandleOnPackageRemoved_ClearsHistory() throws RemoteException {
+ // Enables Notification History setting
+ setUpPrefsForHistory(mUid, true /* =enabled */);
+
+ // Posts a notification to the mTestNotificationChannel.
+ final NotificationRecord notif = generateNotificationRecord(
+ mTestNotificationChannel, 1, null, false);
+ mService.addNotification(notif);
+ StatusBarNotification[] notifs = mBinderService.getActiveNotifications(
+ notif.getSbn().getPackageName());
+ assertEquals(1, notifs.length);
+
+ // Cancels all notifications.
+ mService.cancelAllNotificationsInt(mUid, 0, PKG, null, 0, 0,
+ notif.getUserId(), REASON_CANCEL);
+ waitForIdle();
+ notifs = mBinderService.getActiveNotifications(notif.getSbn().getPackageName());
+ assertEquals(0, notifs.length);
+
+ // Checks that notification history's recently canceled archive contains the notification.
+ notifs = mBinderService.getHistoricalNotificationsWithAttribution(PKG,
+ mContext.getAttributionTag(), 5 /* count */, false /* includeSnoozed */);
+ waitForIdle();
+ assertEquals(1, notifs.length);
+
+ // Remove sthe package that contained the channel
+ simulatePackageRemovedBroadcast(PKG, mUid);
+ waitForIdle();
+
+ // Checks that notification history no longer contains the notification.
+ notifs = mBinderService.getHistoricalNotificationsWithAttribution(
+ PKG, mContext.getAttributionTag(), 5 /* count */, false /* includeSnoozed */);
+ waitForIdle();
+ assertEquals(0, notifs.length);
+ }
+
+ @Test
public void testNotificationHistory_addNoisyNotification() throws Exception {
NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel,
null /* tvExtender */);
diff --git a/services/tests/wmtests/Android.bp b/services/tests/wmtests/Android.bp
index 1b8d746..e83f03d 100644
--- a/services/tests/wmtests/Android.bp
+++ b/services/tests/wmtests/Android.bp
@@ -99,4 +99,7 @@
enabled: false,
},
+ data: [
+ ":OverlayTestApp",
+ ],
}
diff --git a/services/tests/wmtests/AndroidManifest.xml b/services/tests/wmtests/AndroidManifest.xml
index 762e23c..f2a1fe8 100644
--- a/services/tests/wmtests/AndroidManifest.xml
+++ b/services/tests/wmtests/AndroidManifest.xml
@@ -119,6 +119,9 @@
</intent-filter>
</activity>
+ <activity android:name="com.android.server.wm.ActivityRecordInputSinkTests$TestActivity"
+ android:exported="true">
+ </activity>
</application>
<instrumentation
diff --git a/services/tests/wmtests/AndroidTest.xml b/services/tests/wmtests/AndroidTest.xml
index 2717ef90..f8ebead 100644
--- a/services/tests/wmtests/AndroidTest.xml
+++ b/services/tests/wmtests/AndroidTest.xml
@@ -21,6 +21,7 @@
<option name="cleanup-apks" value="true" />
<option name="install-arg" value="-t" />
<option name="test-file-name" value="WmTests.apk" />
+ <option name="test-file-name" value="OverlayTestApp.apk" />
</target_preparer>
<option name="test-tag" value="WmTests" />
diff --git a/services/tests/wmtests/OverlayApp/Android.bp b/services/tests/wmtests/OverlayApp/Android.bp
new file mode 100644
index 0000000..77d5b22
--- /dev/null
+++ b/services/tests/wmtests/OverlayApp/Android.bp
@@ -0,0 +1,19 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_test_helper_app {
+ name: "OverlayTestApp",
+
+ srcs: ["**/*.java"],
+
+ resource_dirs: ["res"],
+
+ certificate: "platform",
+ platform_apis: true,
+}
diff --git a/services/tests/wmtests/OverlayApp/AndroidManifest.xml b/services/tests/wmtests/OverlayApp/AndroidManifest.xml
new file mode 100644
index 0000000..5b4ef57
--- /dev/null
+++ b/services/tests/wmtests/OverlayApp/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.server.wm.overlay_app">
+ <uses-permission android:name="android.permission.INTERNAL_SYSTEM_WINDOW" />
+
+ <application>
+ <activity android:name=".OverlayApp"
+ android:exported="true"
+ android:theme="@style/TranslucentFloatingTheme">
+ </activity>
+ </application>
+</manifest>
diff --git a/services/tests/wmtests/OverlayApp/res/values/styles.xml b/services/tests/wmtests/OverlayApp/res/values/styles.xml
new file mode 100644
index 0000000..fff10a3
--- /dev/null
+++ b/services/tests/wmtests/OverlayApp/res/values/styles.xml
@@ -0,0 +1,26 @@
+<!--
+ ~ 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.
+ -->
+
+<resources>
+ <style name="TranslucentFloatingTheme" >
+ <item name="android:windowIsTranslucent">true</item>
+ <item name="android:windowIsFloating">true</item>
+ <item name="android:windowNoTitle">true</item>
+
+ <!-- Disables starting window. -->
+ <item name="android:windowDisablePreview">true</item>
+ </style>
+</resources>
diff --git a/services/tests/wmtests/OverlayApp/src/com/android/server/wm/overlay_app/OverlayApp.java b/services/tests/wmtests/OverlayApp/src/com/android/server/wm/overlay_app/OverlayApp.java
new file mode 100644
index 0000000..89161c5
--- /dev/null
+++ b/services/tests/wmtests/OverlayApp/src/com/android/server/wm/overlay_app/OverlayApp.java
@@ -0,0 +1,51 @@
+/*
+ * 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.wm.overlay_app;
+
+import android.app.Activity;
+import android.graphics.Color;
+import android.os.Bundle;
+import android.view.Gravity;
+import android.view.WindowManager;
+import android.widget.LinearLayout;
+
+/**
+ * Test app that is translucent not touchable modal.
+ * If launched with "disableInputSink" extra boolean value, this activity disables
+ * ActivityRecordInputSinkEnabled as long as the permission is granted.
+ */
+public class OverlayApp extends Activity {
+ private static final String KEY_DISABLE_INPUT_SINK = "disableInputSink";
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ LinearLayout tv = new LinearLayout(this);
+ tv.setBackgroundColor(Color.GREEN);
+ tv.setPadding(50, 50, 50, 50);
+ tv.setGravity(Gravity.CENTER);
+ setContentView(tv);
+
+ getWindow().addFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL);
+ getWindow().clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
+
+ if (getIntent().getBooleanExtra(KEY_DISABLE_INPUT_SINK, false)) {
+ setActivityRecordInputSinkEnabled(false);
+ }
+ }
+}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordInputSinkTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordInputSinkTests.java
new file mode 100644
index 0000000..3b280d9
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordInputSinkTests.java
@@ -0,0 +1,209 @@
+/*
+ * Copyright 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.wm;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.app.Activity;
+import android.app.ActivityManager;
+import android.app.UiAutomation;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.os.SystemClock;
+import android.platform.test.annotations.RequiresFlagsDisabled;
+import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
+import android.view.MotionEvent;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.window.WindowInfosListenerForTest;
+
+import androidx.test.ext.junit.rules.ActivityScenarioRule;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.MediumTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.window.flags.Flags;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
+
+/**
+ * Internal variant of {@link android.server.wm.window.ActivityRecordInputSinkTests}.
+ */
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class ActivityRecordInputSinkTests {
+ private static final String OVERLAY_APP_PKG = "com.android.server.wm.overlay_app";
+ private static final String OVERLAY_ACTIVITY = OVERLAY_APP_PKG + "/.OverlayApp";
+ private static final String KEY_DISABLE_INPUT_SINK = "disableInputSink";
+
+ @Rule
+ public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
+
+ @Rule
+ public final ActivityScenarioRule<TestActivity> mActivityRule =
+ new ActivityScenarioRule<>(TestActivity.class);
+
+ private UiAutomation mUiAutomation;
+
+ @Before
+ public void setUp() {
+ mUiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
+ }
+
+ @After
+ public void tearDown() {
+ ActivityManager am =
+ InstrumentationRegistry.getInstrumentation().getContext().getSystemService(
+ ActivityManager.class);
+ mUiAutomation.adoptShellPermissionIdentity();
+ try {
+ am.forceStopPackage(OVERLAY_APP_PKG);
+ } finally {
+ mUiAutomation.dropShellPermissionIdentity();
+ }
+ }
+
+ @Test
+ public void testSimpleButtonPress() {
+ injectTapOnButton();
+
+ mActivityRule.getScenario().onActivity(a -> {
+ assertEquals(1, a.mNumClicked);
+ });
+ }
+
+ @Test
+ public void testSimpleButtonPress_withOverlay() throws InterruptedException {
+ startOverlayApp(false);
+ waitForOverlayApp();
+
+ injectTapOnButton();
+
+ mActivityRule.getScenario().onActivity(a -> {
+ assertEquals(0, a.mNumClicked);
+ });
+ }
+
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_ALLOW_DISABLE_ACTIVITY_RECORD_INPUT_SINK)
+ public void testSimpleButtonPress_withOverlayDisableInputSink() throws InterruptedException {
+ startOverlayApp(true);
+ waitForOverlayApp();
+
+ injectTapOnButton();
+
+ mActivityRule.getScenario().onActivity(a -> {
+ assertEquals(1, a.mNumClicked);
+ });
+ }
+
+ @Test
+ @RequiresFlagsDisabled(Flags.FLAG_ALLOW_DISABLE_ACTIVITY_RECORD_INPUT_SINK)
+ public void testSimpleButtonPress_withOverlayDisableInputSink_flagDisabled()
+ throws InterruptedException {
+ startOverlayApp(true);
+ waitForOverlayApp();
+
+ injectTapOnButton();
+
+ mActivityRule.getScenario().onActivity(a -> {
+ assertEquals(0, a.mNumClicked);
+ });
+ }
+
+ private void startOverlayApp(boolean disableInputSink) {
+ String launchCommand = "am start -n " + OVERLAY_ACTIVITY;
+ if (disableInputSink) {
+ launchCommand += " --ez " + KEY_DISABLE_INPUT_SINK + " true";
+ }
+
+ mUiAutomation.adoptShellPermissionIdentity();
+ try {
+ mUiAutomation.executeShellCommand(launchCommand);
+ } finally {
+ mUiAutomation.dropShellPermissionIdentity();
+ }
+ }
+
+ private void waitForOverlayApp() throws InterruptedException {
+ final var listenerHost = new WindowInfosListenerForTest();
+ final var latch = new CountDownLatch(1);
+ final Consumer<List<WindowInfosListenerForTest.WindowInfo>> listener = windowInfos -> {
+ final boolean inputSinkReady = windowInfos.stream().anyMatch(info ->
+ info.isVisible
+ && info.name.contains("ActivityRecordInputSink " + OVERLAY_ACTIVITY));
+ if (inputSinkReady) {
+ latch.countDown();
+ }
+ };
+
+ listenerHost.addWindowInfosListener(listener);
+ try {
+ assertTrue(latch.await(5, TimeUnit.SECONDS));
+ } finally {
+ listenerHost.removeWindowInfosListener(listener);
+ }
+ }
+
+ private void injectTapOnButton() {
+ Rect buttonBounds = new Rect();
+ mActivityRule.getScenario().onActivity(a -> {
+ a.mButton.getBoundsOnScreen(buttonBounds);
+ });
+ final int x = buttonBounds.centerX();
+ final int y = buttonBounds.centerY();
+
+ MotionEvent down = MotionEvent.obtain(SystemClock.uptimeMillis(),
+ SystemClock.uptimeMillis(), MotionEvent.ACTION_DOWN, x, y, 0);
+ mUiAutomation.injectInputEvent(down, true);
+
+ SystemClock.sleep(10);
+
+ MotionEvent up = MotionEvent.obtain(SystemClock.uptimeMillis(), SystemClock.uptimeMillis(),
+ MotionEvent.ACTION_UP, x, y, 0);
+ mUiAutomation.injectInputEvent(up, true);
+
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+ }
+
+ public static class TestActivity extends Activity {
+ int mNumClicked = 0;
+ Button mButton;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mButton = new Button(this);
+ mButton.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT));
+ setContentView(mButton);
+ mButton.setOnClickListener(v -> mNumClicked++);
+ }
+ }
+}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
index e152feb..e31ee11 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
@@ -306,7 +306,7 @@
@Test
public void testCachedStateConfigurationChange() throws RemoteException {
- doNothing().when(mClientLifecycleManager).scheduleTransactionItem(any(), any());
+ doNothing().when(mClientLifecycleManager).scheduleTransactionItemUnlocked(any(), any());
final IApplicationThread thread = mWpc.getThread();
final Configuration newConfig = new Configuration(mWpc.getConfiguration());
newConfig.densityDpi += 100;
@@ -322,18 +322,17 @@
newConfig.densityDpi += 100;
mWpc.onConfigurationChanged(newConfig);
verify(mClientLifecycleManager, never()).scheduleTransactionItem(eq(thread), any());
+ verify(mClientLifecycleManager, never()).scheduleTransactionItemUnlocked(eq(thread), any());
// Cached -> non-cached will send the previous deferred config immediately.
mWpc.setReportedProcState(ActivityManager.PROCESS_STATE_RECEIVER);
final ArgumentCaptor<ConfigurationChangeItem> captor =
ArgumentCaptor.forClass(ConfigurationChangeItem.class);
- verify(mClientLifecycleManager).scheduleTransactionItem(eq(thread), captor.capture());
+ verify(mClientLifecycleManager).scheduleTransactionItemUnlocked(
+ eq(thread), captor.capture());
final ClientTransactionHandler client = mock(ClientTransactionHandler.class);
captor.getValue().preExecute(client);
- final ArgumentCaptor<Configuration> configCaptor =
- ArgumentCaptor.forClass(Configuration.class);
- verify(client).updatePendingConfiguration(configCaptor.capture());
- assertEquals(newConfig, configCaptor.getValue());
+ verify(client).updatePendingConfiguration(newConfig);
}
@Test
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 55fecfc..b167f1b 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -228,6 +228,14 @@
"android.telecom.extra.DEFAULT_CALL_SCREENING_APP_COMPONENT_NAME";
/**
+ * Optional extra to indicate a call should not be added to the call log.
+ *
+ * @hide
+ */
+ public static final String EXTRA_DO_NOT_LOG_CALL =
+ "android.telecom.extra.DO_NOT_LOG_CALL";
+
+ /**
* Extra value used with {@link #ACTION_DEFAULT_CALL_SCREENING_APP_CHANGED} broadcast to
* indicate whether an app is the default call screening app.
* <p>
diff --git a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt
index 9c2899ac..3aee932 100644
--- a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt
+++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt
@@ -20,6 +20,8 @@
import android.app.WallpaperManager
import android.content.res.Resources
import android.platform.test.annotations.Presubmit
+import android.tools.common.datatypes.Region
+import android.tools.common.flicker.subject.layers.LayersTraceSubject
import android.tools.common.flicker.subject.layers.LayersTraceSubject.Companion.VISIBLE_FOR_MORE_THAN_ONE_ENTRY_IGNORE_LAYERS
import android.tools.common.traces.component.ComponentNameMatcher
import android.tools.common.traces.component.ComponentNameMatcher.Companion.SPLASH_SCREEN
@@ -125,27 +127,19 @@
val backgroundColorLayer = ComponentNameMatcher("", "animation-background")
val displayBounds = WindowUtils.getDisplayBounds(flicker.scenario.startRotation)
flicker.assertLayers {
- this.invoke("LAUNCH_NEW_TASK_ACTIVITY coversExactly displayBounds") {
- it.visibleRegion(launchNewTaskApp.componentMatcher).coversExactly(displayBounds)
- }
+ visibleRegionCovers(launchNewTaskApp.componentMatcher, displayBounds)
.isInvisible(backgroundColorLayer)
- .hasNoColor(backgroundColorLayer)
.then()
// Transitioning
.isVisible(backgroundColorLayer)
- .hasColor(backgroundColorLayer)
.then()
// Fully transitioned to simple SIMPLE_ACTIVITY
- .invoke(
- "SIMPLE_ACTIVITY's splashscreen coversExactly displayBounds",
+ .visibleRegionCovers(
+ ComponentSplashScreenMatcher(simpleApp.componentMatcher),
+ displayBounds,
isOptional = true
- ) {
- it.visibleRegion(ComponentSplashScreenMatcher(simpleApp.componentMatcher))
- .coversExactly(displayBounds)
- }
- .invoke("SIMPLE_ACTIVITY coversExactly displayBounds") {
- it.visibleRegion(simpleApp.componentMatcher).coversExactly(displayBounds)
- }
+ )
+ .visibleRegionCovers(simpleApp.componentMatcher, displayBounds)
.isInvisible(backgroundColorLayer)
.hasNoColor(backgroundColorLayer)
.then()
@@ -154,18 +148,12 @@
.hasColor(backgroundColorLayer)
.then()
// Fully transitioned back to LAUNCH_NEW_TASK_ACTIVITY
- .invoke(
- "LAUNCH_NEW_TASK_ACTIVITY's splashscreen coversExactly displayBounds",
+ .visibleRegionCovers(
+ ComponentSplashScreenMatcher(launchNewTaskApp.componentMatcher),
+ displayBounds,
isOptional = true
- ) {
- it.visibleRegion(
- ComponentSplashScreenMatcher(launchNewTaskApp.componentMatcher)
- )
- .coversExactly(displayBounds)
- }
- .invoke("LAUNCH_NEW_TASK_ACTIVITY coversExactly displayBounds") {
- it.visibleRegion(launchNewTaskApp.componentMatcher).coversExactly(displayBounds)
- }
+ )
+ .visibleRegionCovers(launchNewTaskApp.componentMatcher, displayBounds)
.isInvisible(backgroundColorLayer)
.hasNoColor(backgroundColorLayer)
}
@@ -223,6 +211,14 @@
return ComponentNameMatcher(rawComponentMatcher.className)
}
+ private fun LayersTraceSubject.visibleRegionCovers(
+ component: IComponentMatcher,
+ expectedArea: Region,
+ isOptional: Boolean = true
+ ): LayersTraceSubject = invoke("$component coversExactly $expectedArea", isOptional) {
+ it.visibleRegion(component).coversExactly(expectedArea)
+ }
+
@Parameterized.Parameters(name = "{0}")
@JvmStatic
fun getParams() = LegacyFlickerTestFactory.nonRotationTests()
diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeToHomeOnFinishActivityTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeToHomeOnFinishActivityTest.kt
index b44f1a6..c49f8fe 100644
--- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeToHomeOnFinishActivityTest.kt
+++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeToHomeOnFinishActivityTest.kt
@@ -23,10 +23,13 @@
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.device.traces.parsers.toFlickerComponent
import androidx.test.filters.FlakyTest
import com.android.server.wm.flicker.BaseTest
import com.android.server.wm.flicker.helpers.ImeAppHelper
import com.android.server.wm.flicker.helpers.SimpleAppHelper
+import com.android.server.wm.flicker.testapp.ActivityOptions
+import com.android.server.wm.flicker.testapp.ActivityOptions.Ime.Default.ACTION_FINISH_ACTIVITY
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -53,7 +56,12 @@
testApp.launchViaIntent(wmHelper)
testApp.openIME(wmHelper)
}
- transitions { testApp.finishActivity(wmHelper) }
+ transitions {
+ broadcastActionTrigger.doAction(ACTION_FINISH_ACTIVITY)
+ wmHelper.StateSyncBuilder()
+ .withActivityRemoved(ActivityOptions.Ime.Default.COMPONENT.toFlickerComponent())
+ .waitForAndVerify()
+ }
teardown { simpleApp.exit(wmHelper) }
}
diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/OpenImeWindowToFixedPortraitAppTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/OpenImeWindowToFixedPortraitAppTest.kt
index 976ac82..994edc5 100644
--- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/OpenImeWindowToFixedPortraitAppTest.kt
+++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/OpenImeWindowToFixedPortraitAppTest.kt
@@ -28,6 +28,7 @@
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.BaseTest
import com.android.server.wm.flicker.helpers.ImeShownOnAppStartHelper
+import com.android.server.wm.flicker.testapp.ActivityOptions.Ime.Default.ACTION_TOGGLE_ORIENTATION
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -53,7 +54,11 @@
// Enable letterbox when the app calls setRequestedOrientation
device.executeShellCommand("cmd window set-ignore-orientation-request true")
}
- transitions { testApp.toggleFixPortraitOrientation(wmHelper) }
+ transitions {
+ broadcastActionTrigger.doAction(ACTION_TOGGLE_ORIENTATION)
+ // Ensure app relaunching transition finished and the IME was shown
+ testApp.waitIMEShown(wmHelper)
+ }
teardown {
testApp.exit()
device.executeShellCommand("cmd window set-ignore-orientation-request false")
diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromOverviewTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromOverviewTest.kt
index 05babd67..b7a183d 100644
--- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromOverviewTest.kt
+++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromOverviewTest.kt
@@ -23,7 +23,6 @@
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import android.tools.device.helpers.reopenAppFromOverview
import com.android.server.wm.flicker.BaseTest
import com.android.server.wm.flicker.helpers.ImeShownOnAppStartHelper
import com.android.server.wm.flicker.helpers.setRotation
@@ -46,6 +45,7 @@
/** {@inheritDoc} */
override val transition: FlickerBuilder.() -> Unit = {
setup {
+ tapl.expectedRotationCheckEnabled = false
tapl.workspace.switchToOverview().dismissAllTasks()
testApp.launchViaIntent(wmHelper)
testApp.openIME(wmHelper)
@@ -54,7 +54,7 @@
wmHelper.StateSyncBuilder().withRecentsActivityVisible().waitForAndVerify()
}
transitions {
- device.reopenAppFromOverview(wmHelper)
+ tapl.overview.currentTask.open()
wmHelper.StateSyncBuilder().withFullScreenApp(testApp).withImeShown().waitForAndVerify()
}
teardown { testApp.exit(wmHelper) }
diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromQuickSwitchTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromQuickSwitchTest.kt
index aff8e65..6ee5a9a 100644
--- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromQuickSwitchTest.kt
+++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromQuickSwitchTest.kt
@@ -104,7 +104,7 @@
@Presubmit
@Test
- open fun imeLayerIsVisibleWhenSwitchingToImeApp() {
+ fun imeLayerIsVisibleWhenSwitchingToImeApp() {
flicker.assertLayersStart { isVisible(ComponentNameMatcher.IME) }
flicker.assertLayersTag(TAG_IME_VISIBLE) { isVisible(ComponentNameMatcher.IME) }
flicker.assertLayersEnd { isVisible(ComponentNameMatcher.IME) }
diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppTest.kt
index 4ffdcea..1ad5c0d 100644
--- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppTest.kt
+++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppTest.kt
@@ -93,7 +93,7 @@
}
transitions {
testApp.launchViaIntent(wmHelper)
- wmHelper.StateSyncBuilder().withImeShown().waitForAndVerify()
+ testApp.waitIMEShown(wmHelper)
}
}
diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhileDismissingThemedPopupDialogTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhileDismissingThemedPopupDialogTest.kt
index 6ad235c..181a2a2 100644
--- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhileDismissingThemedPopupDialogTest.kt
+++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhileDismissingThemedPopupDialogTest.kt
@@ -23,11 +23,14 @@
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.device.traces.parsers.toFlickerComponent
import android.view.WindowInsets.Type.ime
import android.view.WindowInsets.Type.navigationBars
import android.view.WindowInsets.Type.statusBars
import com.android.server.wm.flicker.BaseTest
import com.android.server.wm.flicker.helpers.ImeShownOnAppStartHelper
+import com.android.server.wm.flicker.testapp.ActivityOptions
+import com.android.server.wm.flicker.testapp.ActivityOptions.Ime.Default.ACTION_START_DIALOG_THEMED_ACTIVITY
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.FixMethodOrder
@@ -50,8 +53,12 @@
override val transition: FlickerBuilder.() -> Unit = {
setup {
testApp.launchViaIntent(wmHelper)
- wmHelper.StateSyncBuilder().withImeShown().waitForAndVerify()
- testApp.startDialogThemedActivity(wmHelper)
+ testApp.waitIMEShown(wmHelper)
+ broadcastActionTrigger.doAction(ACTION_START_DIALOG_THEMED_ACTIVITY)
+ wmHelper.StateSyncBuilder()
+ .withFullScreenApp(
+ ActivityOptions.DialogThemedActivity.COMPONENT.toFlickerComponent())
+ .waitForAndVerify()
// Verify IME insets isn't visible on dialog since it's non-IME focusable window
assertFalse(testApp.getInsetsVisibleFromDialog(ime()))
assertTrue(testApp.getInsetsVisibleFromDialog(statusBars()))
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/BaseTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/BaseTest.kt
index 7c9c05d..ad272a0 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/BaseTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/BaseTest.kt
@@ -17,6 +17,7 @@
package com.android.server.wm.flicker
import android.app.Instrumentation
+import android.content.Intent
import android.platform.test.annotations.Presubmit
import android.tools.common.traces.component.ComponentNameMatcher
import android.tools.device.flicker.junit.FlickerBuilderProvider
@@ -50,6 +51,19 @@
/** Specification of the test transition to execute */
abstract val transition: FlickerBuilder.() -> Unit
+ protected val broadcastActionTrigger = BroadcastActionTrigger(instrumentation)
+
+ // Helper class to process test actions by broadcast.
+ protected class BroadcastActionTrigger(private val instrumentation: Instrumentation) {
+ private fun createIntentWithAction(broadcastAction: String): Intent {
+ return Intent(broadcastAction).setFlags(Intent.FLAG_RECEIVER_FOREGROUND)
+ }
+
+ fun doAction(broadcastAction: String) {
+ instrumentation.context.sendBroadcast(createIntentWithAction(broadcastAction))
+ }
+ }
+
/**
* Entry point for the test runner. It will use this method to initialize and cache flicker
* executions
diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt
index 252f7d3..cb1aab0 100644
--- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt
+++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt
@@ -50,7 +50,7 @@
waitIMEShown(wmHelper)
}
- protected fun waitIMEShown(wmHelper: WindowManagerStateHelper) {
+ fun waitIMEShown(wmHelper: WindowManagerStateHelper) {
wmHelper.StateSyncBuilder().withImeShown().waitForAndVerify()
}
@@ -63,17 +63,4 @@
uiDevice.pressBack()
wmHelper.StateSyncBuilder().withImeGone().waitForAndVerify()
}
-
- open fun finishActivity(wmHelper: WindowManagerStateHelper) {
- val finishButton =
- uiDevice.wait(
- Until.findObject(By.res(packageName, "finish_activity_btn")),
- FIND_TIMEOUT
- )
- requireNotNull(finishButton) {
- "Finish activity button not found, probably IME activity is not on the screen?"
- }
- finishButton.click()
- wmHelper.StateSyncBuilder().withActivityRemoved(this).waitForAndVerify()
- }
}
diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ImeShownOnAppStartHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ImeShownOnAppStartHelper.kt
index d3cee64..0ee7aee 100644
--- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ImeShownOnAppStartHelper.kt
+++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ImeShownOnAppStartHelper.kt
@@ -74,24 +74,6 @@
open(expectedPackage)
}
- fun startDialogThemedActivity(wmHelper: WindowManagerStateHelper) {
- val button =
- uiDevice.wait(
- Until.findObject(By.res(packageName, "start_dialog_themed_activity_btn")),
- FIND_TIMEOUT
- )
-
- requireNotNull(button) {
- "Button not found, this usually happens when the device " +
- "was left in an unknown state (e.g. Screen turned off)"
- }
- button.click()
- wmHelper
- .StateSyncBuilder()
- .withFullScreenApp(ActivityOptions.DialogThemedActivity.COMPONENT.toFlickerComponent())
- .waitForAndVerify()
- }
-
fun dismissDialog(wmHelper: WindowManagerStateHelper) {
val dialog = uiDevice.wait(Until.findObject(By.text("Dialog for test")), FIND_TIMEOUT)
@@ -126,20 +108,4 @@
}
return false
}
-
- fun toggleFixPortraitOrientation(wmHelper: WindowManagerStateHelper) {
- val button =
- uiDevice.wait(
- Until.findObject(By.res(packageName, "toggle_fixed_portrait_btn")),
- FIND_TIMEOUT
- )
- require(button != null) {
- "Button not found, this usually happens when the device " +
- "was left in an unknown state (e.g. Screen turned off)"
- }
- button.click()
- instrumentation.waitForIdleSync()
- // Ensure app relaunching transition finish and the IME has shown
- waitIMEShown(wmHelper)
- }
}
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_ime.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_ime.xml
index fa73e2c..507c1b6 100644
--- a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_ime.xml
+++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_ime.xml
@@ -1,5 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
+<?xml version="1.0" encoding="utf-8"?><!--
Copyright 2018 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,39 +13,17 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:orientation="vertical"
+ android:background="@android:color/holo_green_light"
android:focusableInTouchMode="true"
- android:background="@android:color/holo_green_light">
- <EditText android:id="@+id/plain_text_input"
- android:layout_height="wrap_content"
- android:layout_width="match_parent"
- android:imeOptions="flagNoExtractUi"
- android:inputType="text"/>
- <LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical">
+
+ <EditText
+ android:id="@+id/plain_text_input"
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="horizontal">
- <Button
- android:id="@+id/finish_activity_btn"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="Finish activity" />
- <Button
- android:id="@+id/start_dialog_themed_activity_btn"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="Dialog themed activity" />
- <ToggleButton
- android:id="@+id/toggle_fixed_portrait_btn"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textOn="Portrait (On)"
- android:textOff="Portrait (Off)"
- />
- </LinearLayout>
+ android:layout_height="wrap_content"
+ android:imeOptions="flagNoExtractUi"
+ android:inputType="text" />
</LinearLayout>
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java
index 8b334c0..80c1dd0 100644
--- a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java
@@ -40,6 +40,18 @@
public static final String LABEL = "ImeActivity";
public static final ComponentName COMPONENT = new ComponentName(FLICKER_APP_PACKAGE,
FLICKER_APP_PACKAGE + ".ImeActivity");
+
+ /** Intent action used to finish the test activity. */
+ public static final String ACTION_FINISH_ACTIVITY =
+ FLICKER_APP_PACKAGE + ".ImeActivity.FINISH_ACTIVITY";
+
+ /** Intent action used to start a {@link DialogThemedActivity}. */
+ public static final String ACTION_START_DIALOG_THEMED_ACTIVITY =
+ FLICKER_APP_PACKAGE + ".ImeActivity.START_DIALOG_THEMED_ACTIVITY";
+
+ /** Intent action used to toggle activity orientation. */
+ public static final String ACTION_TOGGLE_ORIENTATION =
+ FLICKER_APP_PACKAGE + ".ImeActivity.TOGGLE_ORIENTATION";
}
public static class AutoFocusActivity {
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ImeActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ImeActivity.java
index d7ee2af..4418b5a 100644
--- a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ImeActivity.java
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ImeActivity.java
@@ -16,12 +16,51 @@
package com.android.server.wm.flicker.testapp;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+
+import static com.android.server.wm.flicker.testapp.ActivityOptions.Ime.Default.ACTION_FINISH_ACTIVITY;
+import static com.android.server.wm.flicker.testapp.ActivityOptions.Ime.Default.ACTION_START_DIALOG_THEMED_ACTIVITY;
+import static com.android.server.wm.flicker.testapp.ActivityOptions.Ime.Default.ACTION_TOGGLE_ORIENTATION;
+
import android.app.Activity;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
import android.os.Bundle;
+import android.util.Log;
import android.view.WindowManager;
-import android.widget.Button;
public class ImeActivity extends Activity {
+
+ private static final String TAG = "ImeActivity";
+
+ /** Receiver used to handle actions coming from the test helper methods. */
+ private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ switch (intent.getAction()) {
+ case ACTION_FINISH_ACTIVITY -> finish();
+ case ACTION_START_DIALOG_THEMED_ACTIVITY -> startActivity(
+ new Intent(context, DialogThemedActivity.class));
+ case ACTION_TOGGLE_ORIENTATION -> {
+ mIsPortrait = !mIsPortrait;
+ setRequestedOrientation(mIsPortrait
+ ? SCREEN_ORIENTATION_PORTRAIT
+ : SCREEN_ORIENTATION_UNSPECIFIED);
+ }
+ default -> Log.w(TAG, "Unhandled action=" + intent.getAction());
+ }
+ }
+ };
+
+ /**
+ * Used to toggle activity orientation between portrait when {@code true} and
+ * unspecified otherwise.
+ */
+ private boolean mIsPortrait = false;
+
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -30,9 +69,17 @@
.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
getWindow().setAttributes(p);
setContentView(R.layout.activity_ime);
- Button button = findViewById(R.id.finish_activity_btn);
- button.setOnClickListener(view -> {
- finish();
- });
+
+ final var filter = new IntentFilter();
+ filter.addAction(ACTION_FINISH_ACTIVITY);
+ filter.addAction(ACTION_START_DIALOG_THEMED_ACTIVITY);
+ filter.addAction(ACTION_TOGGLE_ORIENTATION);
+ registerReceiver(mBroadcastReceiver, filter, Context.RECEIVER_EXPORTED);
+ }
+
+ @Override
+ protected void onDestroy() {
+ unregisterReceiver(mBroadcastReceiver);
+ super.onDestroy();
}
}
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ImeActivityAutoFocus.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ImeActivityAutoFocus.java
index 7ee8deb..cd711f7 100644
--- a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ImeActivityAutoFocus.java
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ImeActivityAutoFocus.java
@@ -16,29 +16,12 @@
package com.android.server.wm.flicker.testapp;
-import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
-import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
-
-import android.content.Intent;
-import android.widget.Button;
-import android.widget.EditText;
-import android.widget.ToggleButton;
-
public class ImeActivityAutoFocus extends ImeActivity {
@Override
protected void onStart() {
super.onStart();
- Button startThemedActivityButton = findViewById(R.id.start_dialog_themed_activity_btn);
- startThemedActivityButton.setOnClickListener(
- button -> startActivity(new Intent(this, DialogThemedActivity.class)));
-
- ToggleButton toggleFixedPortraitButton = findViewById(R.id.toggle_fixed_portrait_btn);
- toggleFixedPortraitButton.setOnCheckedChangeListener(
- (button, isChecked) -> setRequestedOrientation(
- isChecked ? SCREEN_ORIENTATION_PORTRAIT : SCREEN_ORIENTATION_UNSPECIFIED));
-
- EditText editTextField = findViewById(R.id.plain_text_input);
+ final var editTextField = findViewById(R.id.plain_text_input);
editTextField.requestFocus();
}
}
diff --git a/tools/hoststubgen/hoststubgen/framework-policy-override.txt b/tools/hoststubgen/hoststubgen/framework-policy-override.txt
index 493ad56..af3789e 100644
--- a/tools/hoststubgen/hoststubgen/framework-policy-override.txt
+++ b/tools/hoststubgen/hoststubgen/framework-policy-override.txt
@@ -100,3 +100,6 @@
class android.os.BaseBundle stubclass
class android.os.Bundle stubclass
class android.os.PersistableBundle stubclass
+
+class android.os.MessageQueue stubclass
+class android.os.MessageQueue !com.android.hoststubgen.nativesubstitution.MessageQueue_host
diff --git a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/MessageQueue_host.java b/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/MessageQueue_host.java
new file mode 100644
index 0000000..2e47d48
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/MessageQueue_host.java
@@ -0,0 +1,94 @@
+/*
+ * 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.hoststubgen.nativesubstitution;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicLong;
+
+public class MessageQueue_host {
+ private static final AtomicLong sNextId = new AtomicLong(1);
+ private static final Map<Long, MessageQueue_host> sInstances = new ConcurrentHashMap<>();
+
+ private boolean mDeleted = false;
+
+ private final Object mPoller = new Object();
+ private volatile boolean mPolling;
+
+ private void validate() {
+ if (mDeleted) {
+ // TODO: Put more info
+ throw new RuntimeException("MessageQueue already destroyed");
+ }
+ }
+
+ private static MessageQueue_host getInstance(long id) {
+ MessageQueue_host q = sInstances.get(id);
+ if (q == null) {
+ throw new RuntimeException("MessageQueue doesn't exist with id=" + id);
+ }
+ q.validate();
+ return q;
+ }
+
+ public static long nativeInit() {
+ final long id = sNextId.getAndIncrement();
+ final MessageQueue_host q = new MessageQueue_host();
+ sInstances.put(id, q);
+ return id;
+ }
+
+ public static void nativeDestroy(long ptr) {
+ getInstance(ptr).mDeleted = true;
+ sInstances.remove(ptr);
+ }
+
+ public static void nativePollOnce(android.os.MessageQueue queue, long ptr, int timeoutMillis) {
+ var q = getInstance(ptr);
+ synchronized (q.mPoller) {
+ q.mPolling = true;
+ try {
+ if (timeoutMillis == 0) {
+ // Calling epoll_wait() with 0 returns immediately
+ } else if (timeoutMillis == -1) {
+ q.mPoller.wait();
+ } else {
+ q.mPoller.wait(timeoutMillis);
+ }
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ }
+ q.mPolling = false;
+ }
+ }
+
+ public static void nativeWake(long ptr) {
+ var q = getInstance(ptr);
+ synchronized (q.mPoller) {
+ q.mPoller.notifyAll();
+ }
+ }
+
+ public static boolean nativeIsPolling(long ptr) {
+ var q = getInstance(ptr);
+ return q.mPolling;
+ }
+
+ public static void nativeSetFileDescriptorEvents(long ptr, int fd, int events) {
+ throw new UnsupportedOperationException();
+ }
+}
diff --git a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/Parcel_host.java b/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/Parcel_host.java
index 4a3a798..2255345 100644
--- a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/Parcel_host.java
+++ b/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/Parcel_host.java
@@ -27,16 +27,17 @@
/**
* Tentative, partial implementation of the Parcel native methods, using Java's
- * {@link ByteBuffer}. It turned out there's enough semantics differences between Parcel
- * and {@link ByteBuffer}, so it didn't actually work.
- * (e.g. Parcel seems to allow moving the data position to be beyond its size? Which
+ * {@code byte[]}.
+ * (We don't use a {@link ByteBuffer} because there's enough semantics differences between Parcel
+ * and {@link ByteBuffer}, and it didn't work out.
+ * e.g. Parcel seems to allow moving the data position to be beyond its size? Which
* {@link ByteBuffer} wouldn't allow...)
*/
public class Parcel_host {
private Parcel_host() {
}
- private static final AtomicLong sNextId = new AtomicLong(0);
+ private static final AtomicLong sNextId = new AtomicLong(1);
private static final Map<Long, Parcel_host> sInstances = new ConcurrentHashMap<>();
diff --git a/tools/hoststubgen/hoststubgen/invoketest/hoststubgen-invoke-test.sh b/tools/hoststubgen/hoststubgen/invoketest/hoststubgen-invoke-test.sh
index 89daa20..85038be 100755
--- a/tools/hoststubgen/hoststubgen/invoketest/hoststubgen-invoke-test.sh
+++ b/tools/hoststubgen/hoststubgen/invoketest/hoststubgen-invoke-test.sh
@@ -13,6 +13,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+# This command is expected to be executed with: atest hoststubgen-invoke-test
+
set -e # Exit when any command files
# This script runs HostStubGen directly with various arguments and make sure
@@ -35,6 +37,12 @@
mkdir -p $TEMP
fi
+cleanup_temp() {
+ rm -fr $TEMP/*
+}
+
+cleanup_temp
+
JAR=hoststubgen-test-tiny-framework.jar
STUB=$TEMP/stub.jar
IMPL=$TEMP/impl.jar
@@ -47,12 +55,10 @@
# HostStubGen result in it.
HOSTSTUBGEN_RC=0
-# Define the functions to
-
-
# Note, because the build rule will only install hoststubgen.jar, but not the wrapper script,
# we need to execute it manually with the java command.
hoststubgen() {
+ echo "Running hoststubgen with: $*"
java -jar ./hoststubgen.jar "$@"
}
@@ -62,7 +68,7 @@
echo "# Test: $test_name"
- rm -f $HOSTSTUBGEN_OUT
+ cleanup_temp
local filter_arg=""
@@ -73,11 +79,21 @@
cat $ANNOTATION_FILTER
fi
+ local stub_arg=""
+ local impl_arg=""
+
+ if [[ "$STUB" != "" ]] ; then
+ stub_arg="--out-stub-jar $STUB"
+ fi
+ if [[ "$IMPL" != "" ]] ; then
+ impl_arg="--out-impl-jar $IMPL"
+ fi
+
hoststubgen \
--debug \
--in-jar $JAR \
- --out-stub-jar $STUB \
- --out-impl-jar $IMPL \
+ $stub_arg \
+ $impl_arg \
--stub-annotation \
android.hosttest.annotation.HostSideTestStub \
--keep-annotation \
@@ -105,6 +121,21 @@
return 0
}
+assert_file_generated() {
+ local file="$1"
+ if [[ "$file" == "" ]] ; then
+ if [[ -f "$file" ]] ; then
+ echo "HostStubGen shouldn't have generated $file"
+ return 1
+ fi
+ else
+ if ! [[ -f "$file" ]] ; then
+ echo "HostStubGen didn't generate $file"
+ return 1
+ fi
+ fi
+}
+
run_hoststubgen_for_success() {
run_hoststubgen "$@"
@@ -112,6 +143,9 @@
echo "HostStubGen expected to finish successfully, but failed with $rc"
return 1
fi
+
+ assert_file_generated "$STUB"
+ assert_file_generated "$IMPL"
}
run_hoststubgen_for_failure() {
@@ -189,6 +223,11 @@
* # All other classes allowed
"
+STUB="" run_hoststubgen_for_success "No stub generation" ""
+
+IMPL="" run_hoststubgen_for_success "No impl generation" ""
+
+STUB="" IMPL="" run_hoststubgen_for_success "No stub, no impl generation" ""
echo "All tests passed"
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt
index 07bd2dc..3cdddc2 100644
--- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt
@@ -237,8 +237,8 @@
*/
private fun convert(
inJar: String,
- outStubJar: String,
- outImplJar: String,
+ outStubJar: String?,
+ outImplJar: String?,
filter: OutputFilter,
enableChecker: Boolean,
classes: ClassNodes,
@@ -254,8 +254,8 @@
log.withIndent {
// Open the input jar file and process each entry.
ZipFile(inJar).use { inZip ->
- ZipOutputStream(FileOutputStream(outStubJar)).use { stubOutStream ->
- ZipOutputStream(FileOutputStream(outImplJar)).use { implOutStream ->
+ maybeWithZipOutputStream(outStubJar) { stubOutStream ->
+ maybeWithZipOutputStream(outImplJar) { implOutStream ->
val inEntries = inZip.entries()
while (inEntries.hasMoreElements()) {
val entry = inEntries.nextElement()
@@ -265,22 +265,29 @@
log.i("Converted all entries.")
}
}
- log.i("Created stub: $outStubJar")
- log.i("Created impl: $outImplJar")
+ outStubJar?.let { log.i("Created stub: $it") }
+ outImplJar?.let { log.i("Created impl: $it") }
}
}
val end = System.currentTimeMillis()
log.v("Done transforming the jar in %.1f second(s).", (end - start) / 1000.0)
}
+ private fun <T> maybeWithZipOutputStream(filename: String?, block: (ZipOutputStream?) -> T): T {
+ if (filename == null) {
+ return block(null)
+ }
+ return ZipOutputStream(FileOutputStream(filename)).use(block)
+ }
+
/**
* Convert a single ZIP entry, which may or may not be a class file.
*/
private fun convertSingleEntry(
inZip: ZipFile,
entry: ZipEntry,
- stubOutStream: ZipOutputStream,
- implOutStream: ZipOutputStream,
+ stubOutStream: ZipOutputStream?,
+ implOutStream: ZipOutputStream?,
filter: OutputFilter,
packageRedirector: PackageRedirectRemapper,
enableChecker: Boolean,
@@ -316,8 +323,8 @@
// Unknown type, we just copy it to both output zip files.
// TODO: We probably shouldn't do it for stub jar?
log.v("Copying: %s", entry.name)
- copyZipEntry(inZip, entry, stubOutStream)
- copyZipEntry(inZip, entry, implOutStream)
+ stubOutStream?.let { copyZipEntry(inZip, entry, it) }
+ implOutStream?.let { copyZipEntry(inZip, entry, it) }
}
}
@@ -346,8 +353,8 @@
private fun processSingleClass(
inZip: ZipFile,
entry: ZipEntry,
- stubOutStream: ZipOutputStream,
- implOutStream: ZipOutputStream,
+ stubOutStream: ZipOutputStream?,
+ implOutStream: ZipOutputStream?,
filter: OutputFilter,
packageRedirector: PackageRedirectRemapper,
enableChecker: Boolean,
@@ -361,7 +368,7 @@
return
}
// Generate stub first.
- if (classPolicy.policy.needsInStub) {
+ if (stubOutStream != null && classPolicy.policy.needsInStub) {
log.v("Creating stub class: %s Policy: %s", classInternalName, classPolicy)
log.withIndent {
BufferedInputStream(inZip.getInputStream(entry)).use { bis ->
@@ -374,8 +381,8 @@
}
}
}
- log.v("Creating impl class: %s Policy: %s", classInternalName, classPolicy)
- if (classPolicy.policy.needsInImpl) {
+ if (implOutStream != null && classPolicy.policy.needsInImpl) {
+ log.v("Creating impl class: %s Policy: %s", classInternalName, classPolicy)
log.withIndent {
BufferedInputStream(inZip.getInputStream(entry)).use { bis ->
val newEntry = ZipEntry(entry.name)
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt
index da53487..83f873d 100644
--- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt
@@ -28,10 +28,10 @@
var inJar: String = "",
/** Output stub jar file */
- var outStubJar: String = "",
+ var outStubJar: String? = null,
/** Output implementation jar file */
- var outImplJar: String = "",
+ var outImplJar: String? = null,
var inputJarDumpFile: String? = null,
@@ -71,7 +71,7 @@
var enablePreTrace: Boolean = false,
var enablePostTrace: Boolean = false,
- var enableNonStubMethodCallDetection: Boolean = true,
+ var enableNonStubMethodCallDetection: Boolean = false,
) {
companion object {
@@ -209,11 +209,14 @@
if (ret.inJar.isEmpty()) {
throw ArgumentsException("Required option missing: --in-jar")
}
- if (ret.outStubJar.isEmpty()) {
- throw ArgumentsException("Required option missing: --out-stub-jar")
+ if (ret.outStubJar == null && ret.outImplJar == null) {
+ log.w("Neither --out-stub-jar nor --out-impl-jar is set." +
+ " $COMMAND_NAME will not generate jar files.")
}
- if (ret.outImplJar.isEmpty()) {
- throw ArgumentsException("Required option missing: --out-impl-jar")
+
+ if (ret.enableNonStubMethodCallDetection) {
+ log.w("--enable-non-stub-method-check is not fully implemented yet." +
+ " See the todo in doesMethodNeedNonStubCallCheck().")
}
return ret
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/asm/ClassNodes.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/asm/ClassNodes.kt
index 4df0bfc..bc34ef0 100644
--- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/asm/ClassNodes.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/asm/ClassNodes.kt
@@ -1,3 +1,18 @@
+/*
+ * 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.hoststubgen.asm
import com.android.hoststubgen.ClassParseException
@@ -40,6 +55,11 @@
return findClass(name) ?: throw ClassParseException("Class $name not found")
}
+ /** @return whether a class exists or not */
+ fun hasClass(name: String): Boolean {
+ return mAllClasses.containsKey(name.toJvmClassName())
+ }
+
/** Find a field, which may not exist. */
fun findField(
className: String,
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/AndroidHeuristicsFilter.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/AndroidHeuristicsFilter.kt
new file mode 100644
index 0000000..356e1fa
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/AndroidHeuristicsFilter.kt
@@ -0,0 +1,43 @@
+/*
+ * 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.hoststubgen.filters
+
+import com.android.hoststubgen.asm.ClassNodes
+
+/**
+ * Filter that deals with Android specific heuristics.
+ */
+class AndroidHeuristicsFilter(
+ private val classes: ClassNodes,
+ val aidlPolicy: FilterPolicyWithReason?,
+ fallback: OutputFilter
+) : DelegatingFilter(fallback) {
+ override fun getPolicyForClass(className: String): FilterPolicyWithReason {
+ if (aidlPolicy != null && classes.isAidlClass(className)) {
+ return aidlPolicy
+ }
+ return super.getPolicyForClass(className)
+ }
+}
+
+/**
+ * @return if a given class "seems like" an AIDL (top-level) class.
+ */
+private fun ClassNodes.isAidlClass(className: String): Boolean {
+ return hasClass(className) &&
+ hasClass("$className\$Stub") &&
+ hasClass("$className\$Proxy")
+}
\ No newline at end of file
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt
index 416f085..b4354ba 100644
--- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt
@@ -58,10 +58,12 @@
): OutputFilter {
log.i("Loading offloaded annotations from $filename ...")
log.withIndent {
- val ret = InMemoryOutputFilter(classes, fallback)
+ val imf = InMemoryOutputFilter(classes, fallback)
var lineNo = 0
+ var aidlPolicy: FilterPolicy? = null
+
try {
BufferedReader(FileReader(filename)).use { reader ->
var className = ""
@@ -79,6 +81,9 @@
continue // skip empty lines.
}
+
+ // TODO: Method too long, break it up.
+
val fields = line.split(whitespaceRegex).toTypedArray()
when (fields[0].lowercase()) {
"c", "class" -> {
@@ -86,14 +91,27 @@
throw ParseException("Class ('c') expects 2 fields.")
}
className = fields[1]
+
+ val classType = resolveSpecialClass(className)
+
if (fields[2].startsWith("!")) {
+ if (classType != SpecialClass.NotSpecial) {
+ // We could support it, but not needed at least for now.
+ throw ParseException(
+ "Special class can't have a substitution")
+ }
// It's a native-substitution.
val toClass = fields[2].substring(1)
- ret.setNativeSubstitutionClass(className, toClass)
+ imf.setNativeSubstitutionClass(className, toClass)
} else if (fields[2].startsWith("~")) {
+ if (classType != SpecialClass.NotSpecial) {
+ // We could support it, but not needed at least for now.
+ throw ParseException(
+ "Special class can't have a class load hook")
+ }
// It's a class-load hook
val callback = fields[2].substring(1)
- ret.setClassLoadHook(className, callback)
+ imf.setClassLoadHook(className, callback)
} else {
val policy = parsePolicy(fields[2])
if (!policy.isUsableWithClasses) {
@@ -101,8 +119,20 @@
}
Objects.requireNonNull(className)
- // TODO: Duplicate check, etc
- ret.setPolicyForClass(className, policy.withReason(FILTER_REASON))
+ when (classType) {
+ SpecialClass.NotSpecial -> {
+ // TODO: Duplicate check, etc
+ imf.setPolicyForClass(
+ className, policy.withReason(FILTER_REASON))
+ }
+ SpecialClass.Aidl -> {
+ if (aidlPolicy != null) {
+ throw ParseException(
+ "Policy for AIDL classes already defined")
+ }
+ aidlPolicy = policy
+ }
+ }
}
}
@@ -118,7 +148,7 @@
Objects.requireNonNull(className)
// TODO: Duplicate check, etc
- ret.setPolicyForField(className, name, policy.withReason(FILTER_REASON))
+ imf.setPolicyForField(className, name, policy.withReason(FILTER_REASON))
}
"m", "method" -> {
@@ -135,7 +165,7 @@
Objects.requireNonNull(className)
- ret.setPolicyForMethod(className, name, signature,
+ imf.setPolicyForMethod(className, name, signature,
policy.withReason(FILTER_REASON))
if (policy.isSubstitute) {
val fromName = fields[3].substring(1)
@@ -146,12 +176,12 @@
}
// Set the policy for the "from" method.
- ret.setPolicyForMethod(className, fromName, signature,
+ imf.setPolicyForMethod(className, fromName, signature,
policy.getSubstitutionBasePolicy()
.withReason(FILTER_REASON))
// Keep "from" -> "to" mapping.
- ret.setRenameTo(className, fromName, signature, name)
+ imf.setRenameTo(className, fromName, signature, name)
}
}
@@ -164,10 +194,32 @@
} catch (e: ParseException) {
throw e.withSourceInfo(filename, lineNo)
}
+
+ var ret: OutputFilter = imf
+ aidlPolicy?.let { policy ->
+ log.d("AndroidHeuristicsFilter enabled")
+ ret = AndroidHeuristicsFilter(
+ classes, policy.withReason("$FILTER_REASON (AIDL)"), imf)
+ }
return ret
}
}
+private enum class SpecialClass {
+ NotSpecial,
+ Aidl,
+}
+
+private fun resolveSpecialClass(className: String): SpecialClass {
+ if (!className.startsWith(":")) {
+ return SpecialClass.NotSpecial
+ }
+ when (className.lowercase()) {
+ ":aidl" -> return SpecialClass.Aidl
+ }
+ throw ParseException("Invalid special class name \"$className\"")
+}
+
private fun parsePolicy(s: String): FilterPolicy {
return when (s.lowercase()) {
"s", "stub" -> FilterPolicy.Stub
diff --git a/tools/hoststubgen/hoststubgen/test-framework/README.md b/tools/hoststubgen/hoststubgen/test-framework/README.md
index 20e2f87..f616ad6 100644
--- a/tools/hoststubgen/hoststubgen/test-framework/README.md
+++ b/tools/hoststubgen/hoststubgen/test-framework/README.md
@@ -14,12 +14,6 @@
$ atest --no-bazel-mode HostStubGenTest-framework-test-host-test
```
-- With `run-ravenwood-test`
-
-```
-$ run-ravenwood-test HostStubGenTest-framework-test-host-test
-```
-
- Advanced option: `run-test-without-atest.sh` runs the test without using `atest` or `run-ravenwood-test`
```
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/README.md b/tools/hoststubgen/hoststubgen/test-tiny-framework/README.md
index f3c0450..3bfad9b 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/README.md
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/README.md
@@ -13,12 +13,6 @@
$ atest hoststubgen-test-tiny-test
```
-- With `run-ravenwood-test` should work too. This is the proper way to run it.
-
-```
-$ run-ravenwood-test hoststubgen-test-tiny-test
-```
-
- `run-test-manually.sh` also run the test, but it builds the stub/impl jars and the test without
using the build system. This is useful for debugging the tool.
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt
index 673d3e8..214de59 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt
@@ -223,6 +223,103 @@
java.lang.annotation.Target(
value=[Ljava/lang/annotation/ElementType;.TYPE,Ljava/lang/annotation/ElementType;.FIELD,Ljava/lang/annotation/ElementType;.METHOD]
)
+## Class: com/android/hoststubgen/test/tinyframework/IPretendingAidl$Proxy.class
+ Compiled from "IPretendingAidl.java"
+public class com.android.hoststubgen.test.tinyframework.IPretendingAidl$Proxy
+ minor version: 0
+ major version: 61
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/IPretendingAidl$Proxy
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 2, attributes: 3
+ public com.android.hoststubgen.test.tinyframework.IPretendingAidl$Proxy();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/IPretendingAidl$Proxy;
+
+ public static int addTwo(int);
+ descriptor: (I)I
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=2, locals=1, args_size=1
+ x: iload_0
+ x: iconst_2
+ x: iadd
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 4 0 a I
+}
+SourceFile: "IPretendingAidl.java"
+NestHost: class com/android/hoststubgen/test/tinyframework/IPretendingAidl
+InnerClasses:
+ public static #x= #x of #x; // Proxy=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Proxy of class com/android/hoststubgen/test/tinyframework/IPretendingAidl
+## Class: com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub.class
+ Compiled from "IPretendingAidl.java"
+public class com.android.hoststubgen.test.tinyframework.IPretendingAidl$Stub
+ minor version: 0
+ major version: 61
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 2, attributes: 3
+ public com.android.hoststubgen.test.tinyframework.IPretendingAidl$Stub();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub;
+
+ public static int addOne(int);
+ descriptor: (I)I
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=2, locals=1, args_size=1
+ x: iload_0
+ x: iconst_1
+ x: iadd
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 4 0 a I
+}
+SourceFile: "IPretendingAidl.java"
+NestHost: class com/android/hoststubgen/test/tinyframework/IPretendingAidl
+InnerClasses:
+ public static #x= #x of #x; // Stub=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub of class com/android/hoststubgen/test/tinyframework/IPretendingAidl
+## Class: com/android/hoststubgen/test/tinyframework/IPretendingAidl.class
+ Compiled from "IPretendingAidl.java"
+public interface com.android.hoststubgen.test.tinyframework.IPretendingAidl
+ minor version: 0
+ major version: 61
+ flags: (0x0601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT
+ this_class: #x // com/android/hoststubgen/test/tinyframework/IPretendingAidl
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 0, attributes: 3
+}
+SourceFile: "IPretendingAidl.java"
+NestMembers:
+ com/android/hoststubgen/test/tinyframework/IPretendingAidl$Proxy
+ com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub
+InnerClasses:
+ public static #x= #x of #x; // Proxy=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Proxy of class com/android/hoststubgen/test/tinyframework/IPretendingAidl
+ public static #x= #x of #x; // Stub=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub of class com/android/hoststubgen/test/tinyframework/IPretendingAidl
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl.class
Compiled from "TinyFrameworkCallerCheck.java"
class com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck$Impl
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/02-hoststubgen-test-tiny-framework-host-stub-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/02-hoststubgen-test-tiny-framework-host-stub-dump.txt
index d12588a..9031228 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/02-hoststubgen-test-tiny-framework-host-stub-dump.txt
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/02-hoststubgen-test-tiny-framework-host-stub-dump.txt
@@ -1,3 +1,105 @@
+## Class: com/android/hoststubgen/test/tinyframework/IPretendingAidl$Proxy.class
+ Compiled from "IPretendingAidl.java"
+public class com.android.hoststubgen.test.tinyframework.IPretendingAidl$Proxy
+ minor version: 0
+ major version: 61
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/IPretendingAidl$Proxy
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 2, attributes: 4
+ public com.android.hoststubgen.test.tinyframework.IPretendingAidl$Proxy();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=3, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+
+ public static int addTwo(int);
+ descriptor: (I)I
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=3, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+}
+InnerClasses:
+ public static #x= #x of #x; // Proxy=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Proxy of class com/android/hoststubgen/test/tinyframework/IPretendingAidl
+SourceFile: "IPretendingAidl.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+NestHost: class com/android/hoststubgen/test/tinyframework/IPretendingAidl
+## Class: com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub.class
+ Compiled from "IPretendingAidl.java"
+public class com.android.hoststubgen.test.tinyframework.IPretendingAidl$Stub
+ minor version: 0
+ major version: 61
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 2, attributes: 4
+ public com.android.hoststubgen.test.tinyframework.IPretendingAidl$Stub();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=3, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+
+ public static int addOne(int);
+ descriptor: (I)I
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=3, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+}
+InnerClasses:
+ public static #x= #x of #x; // Stub=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub of class com/android/hoststubgen/test/tinyframework/IPretendingAidl
+SourceFile: "IPretendingAidl.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+NestHost: class com/android/hoststubgen/test/tinyframework/IPretendingAidl
+## Class: com/android/hoststubgen/test/tinyframework/IPretendingAidl.class
+ Compiled from "IPretendingAidl.java"
+public interface com.android.hoststubgen.test.tinyframework.IPretendingAidl
+ minor version: 0
+ major version: 61
+ flags: (0x0601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT
+ this_class: #x // com/android/hoststubgen/test/tinyframework/IPretendingAidl
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 0, attributes: 4
+}
+InnerClasses:
+ public static #x= #x of #x; // Proxy=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Proxy of class com/android/hoststubgen/test/tinyframework/IPretendingAidl
+ public static #x= #x of #x; // Stub=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub of class com/android/hoststubgen/test/tinyframework/IPretendingAidl
+SourceFile: "IPretendingAidl.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+NestMembers:
+ com/android/hoststubgen/test/tinyframework/IPretendingAidl$Proxy
+ com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl.class
Compiled from "TinyFrameworkCallerCheck.java"
class com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck$Impl
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/03-hoststubgen-test-tiny-framework-host-impl-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/03-hoststubgen-test-tiny-framework-host-impl-dump.txt
index 97fb64f..e01f49b 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/03-hoststubgen-test-tiny-framework-host-impl-dump.txt
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/03-hoststubgen-test-tiny-framework-host-impl-dump.txt
@@ -205,6 +205,118 @@
java.lang.annotation.Retention(
value=Ljava/lang/annotation/RetentionPolicy;.CLASS
)
+## Class: com/android/hoststubgen/test/tinyframework/IPretendingAidl$Proxy.class
+ Compiled from "IPretendingAidl.java"
+public class com.android.hoststubgen.test.tinyframework.IPretendingAidl$Proxy
+ minor version: 0
+ major version: 61
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/IPretendingAidl$Proxy
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 2, attributes: 4
+ public com.android.hoststubgen.test.tinyframework.IPretendingAidl$Proxy();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/IPretendingAidl$Proxy;
+
+ public static int addTwo(int);
+ descriptor: (I)I
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=2, locals=1, args_size=1
+ x: iload_0
+ x: iconst_2
+ x: iadd
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 4 0 a I
+}
+InnerClasses:
+ public static #x= #x of #x; // Proxy=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Proxy of class com/android/hoststubgen/test/tinyframework/IPretendingAidl
+SourceFile: "IPretendingAidl.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+NestHost: class com/android/hoststubgen/test/tinyframework/IPretendingAidl
+## Class: com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub.class
+ Compiled from "IPretendingAidl.java"
+public class com.android.hoststubgen.test.tinyframework.IPretendingAidl$Stub
+ minor version: 0
+ major version: 61
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 2, attributes: 4
+ public com.android.hoststubgen.test.tinyframework.IPretendingAidl$Stub();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub;
+
+ public static int addOne(int);
+ descriptor: (I)I
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=2, locals=1, args_size=1
+ x: iload_0
+ x: iconst_1
+ x: iadd
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 4 0 a I
+}
+InnerClasses:
+ public static #x= #x of #x; // Stub=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub of class com/android/hoststubgen/test/tinyframework/IPretendingAidl
+SourceFile: "IPretendingAidl.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+NestHost: class com/android/hoststubgen/test/tinyframework/IPretendingAidl
+## Class: com/android/hoststubgen/test/tinyframework/IPretendingAidl.class
+ Compiled from "IPretendingAidl.java"
+public interface com.android.hoststubgen.test.tinyframework.IPretendingAidl
+ minor version: 0
+ major version: 61
+ flags: (0x0601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT
+ this_class: #x // com/android/hoststubgen/test/tinyframework/IPretendingAidl
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 0, attributes: 4
+}
+InnerClasses:
+ public static #x= #x of #x; // Proxy=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Proxy of class com/android/hoststubgen/test/tinyframework/IPretendingAidl
+ public static #x= #x of #x; // Stub=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub of class com/android/hoststubgen/test/tinyframework/IPretendingAidl
+SourceFile: "IPretendingAidl.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+NestMembers:
+ com/android/hoststubgen/test/tinyframework/IPretendingAidl$Proxy
+ com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl.class
Compiled from "TinyFrameworkCallerCheck.java"
class com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck$Impl
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/12-hoststubgen-test-tiny-framework-host-ext-stub-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/12-hoststubgen-test-tiny-framework-host-ext-stub-dump.txt
index d12588a..9031228 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/12-hoststubgen-test-tiny-framework-host-ext-stub-dump.txt
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/12-hoststubgen-test-tiny-framework-host-ext-stub-dump.txt
@@ -1,3 +1,105 @@
+## Class: com/android/hoststubgen/test/tinyframework/IPretendingAidl$Proxy.class
+ Compiled from "IPretendingAidl.java"
+public class com.android.hoststubgen.test.tinyframework.IPretendingAidl$Proxy
+ minor version: 0
+ major version: 61
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/IPretendingAidl$Proxy
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 2, attributes: 4
+ public com.android.hoststubgen.test.tinyframework.IPretendingAidl$Proxy();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=3, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+
+ public static int addTwo(int);
+ descriptor: (I)I
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=3, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+}
+InnerClasses:
+ public static #x= #x of #x; // Proxy=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Proxy of class com/android/hoststubgen/test/tinyframework/IPretendingAidl
+SourceFile: "IPretendingAidl.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+NestHost: class com/android/hoststubgen/test/tinyframework/IPretendingAidl
+## Class: com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub.class
+ Compiled from "IPretendingAidl.java"
+public class com.android.hoststubgen.test.tinyframework.IPretendingAidl$Stub
+ minor version: 0
+ major version: 61
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 2, attributes: 4
+ public com.android.hoststubgen.test.tinyframework.IPretendingAidl$Stub();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=3, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+
+ public static int addOne(int);
+ descriptor: (I)I
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=3, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+}
+InnerClasses:
+ public static #x= #x of #x; // Stub=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub of class com/android/hoststubgen/test/tinyframework/IPretendingAidl
+SourceFile: "IPretendingAidl.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+NestHost: class com/android/hoststubgen/test/tinyframework/IPretendingAidl
+## Class: com/android/hoststubgen/test/tinyframework/IPretendingAidl.class
+ Compiled from "IPretendingAidl.java"
+public interface com.android.hoststubgen.test.tinyframework.IPretendingAidl
+ minor version: 0
+ major version: 61
+ flags: (0x0601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT
+ this_class: #x // com/android/hoststubgen/test/tinyframework/IPretendingAidl
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 0, attributes: 4
+}
+InnerClasses:
+ public static #x= #x of #x; // Proxy=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Proxy of class com/android/hoststubgen/test/tinyframework/IPretendingAidl
+ public static #x= #x of #x; // Stub=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub of class com/android/hoststubgen/test/tinyframework/IPretendingAidl
+SourceFile: "IPretendingAidl.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+NestMembers:
+ com/android/hoststubgen/test/tinyframework/IPretendingAidl$Proxy
+ com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl.class
Compiled from "TinyFrameworkCallerCheck.java"
class com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck$Impl
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-impl-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-impl-dump.txt
index 8035189..5246355 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-impl-dump.txt
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-impl-dump.txt
@@ -289,6 +289,167 @@
java.lang.annotation.Retention(
value=Ljava/lang/annotation/RetentionPolicy;.CLASS
)
+## Class: com/android/hoststubgen/test/tinyframework/IPretendingAidl$Proxy.class
+ Compiled from "IPretendingAidl.java"
+public class com.android.hoststubgen.test.tinyframework.IPretendingAidl$Proxy
+ minor version: 0
+ major version: 61
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/IPretendingAidl$Proxy
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 3, attributes: 4
+ private static {};
+ descriptor: ()V
+ flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Proxy
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: return
+
+ public com.android.hoststubgen.test.tinyframework.IPretendingAidl$Proxy();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Proxy
+ x: ldc #x // String <init>
+ x: ldc #x // String ()V
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 5 0 this Lcom/android/hoststubgen/test/tinyframework/IPretendingAidl$Proxy;
+
+ public static int addTwo(int);
+ descriptor: (I)I
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Proxy
+ x: ldc #x // String addTwo
+ x: ldc #x // String (I)I
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: iload_0
+ x: iconst_2
+ x: iadd
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 4 0 a I
+}
+InnerClasses:
+ public static #x= #x of #x; // Proxy=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Proxy of class com/android/hoststubgen/test/tinyframework/IPretendingAidl
+SourceFile: "IPretendingAidl.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+NestHost: class com/android/hoststubgen/test/tinyframework/IPretendingAidl
+## Class: com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub.class
+ Compiled from "IPretendingAidl.java"
+public class com.android.hoststubgen.test.tinyframework.IPretendingAidl$Stub
+ minor version: 0
+ major version: 61
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 3, attributes: 4
+ private static {};
+ descriptor: ()V
+ flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: return
+
+ public com.android.hoststubgen.test.tinyframework.IPretendingAidl$Stub();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub
+ x: ldc #x // String <init>
+ x: ldc #x // String ()V
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 5 0 this Lcom/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub;
+
+ public static int addOne(int);
+ descriptor: (I)I
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub
+ x: ldc #x // String addOne
+ x: ldc #x // String (I)I
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: iload_0
+ x: iconst_1
+ x: iadd
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 4 0 a I
+}
+InnerClasses:
+ public static #x= #x of #x; // Stub=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub of class com/android/hoststubgen/test/tinyframework/IPretendingAidl
+SourceFile: "IPretendingAidl.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+NestHost: class com/android/hoststubgen/test/tinyframework/IPretendingAidl
+## Class: com/android/hoststubgen/test/tinyframework/IPretendingAidl.class
+ Compiled from "IPretendingAidl.java"
+public interface com.android.hoststubgen.test.tinyframework.IPretendingAidl
+ minor version: 0
+ major version: 61
+ flags: (0x0601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT
+ this_class: #x // com/android/hoststubgen/test/tinyframework/IPretendingAidl
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 0, methods: 1, attributes: 4
+ private static {};
+ descriptor: ()V
+ flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/IPretendingAidl
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: return
+}
+InnerClasses:
+ public static #x= #x of #x; // Proxy=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Proxy of class com/android/hoststubgen/test/tinyframework/IPretendingAidl
+ public static #x= #x of #x; // Stub=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub of class com/android/hoststubgen/test/tinyframework/IPretendingAidl
+SourceFile: "IPretendingAidl.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+NestMembers:
+ com/android/hoststubgen/test/tinyframework/IPretendingAidl$Proxy
+ com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl.class
Compiled from "TinyFrameworkCallerCheck.java"
class com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck$Impl
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/policy-override-tiny-framework.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/policy-override-tiny-framework.txt
index 079d2a8..9b6b6e4 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/policy-override-tiny-framework.txt
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/policy-override-tiny-framework.txt
@@ -15,3 +15,6 @@
# Class load hook
class com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy ~com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded
+
+# Heuristics rule: Stub all the AIDL classes.
+class :aidl stubclass
\ No newline at end of file
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/IPretendingAidl.java b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/IPretendingAidl.java
new file mode 100644
index 0000000..583e13c
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/IPretendingAidl.java
@@ -0,0 +1,35 @@
+/*
+ * 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.hoststubgen.test.tinyframework;
+
+/**
+ * An interface that matches the "AIDL detection heuristics' logic.
+ *
+ * The "class :aidl" line in the text policy file will control the visibility of it.
+ */
+public interface IPretendingAidl {
+ public static class Stub {
+ public static int addOne(int a) {
+ return a + 1;
+ }
+ }
+
+ public static class Proxy {
+ public static int addTwo(int a) {
+ return a + 2;
+ }
+ }
+}
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassTest.java b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassTest.java
index d04ca52..0d52791 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassTest.java
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassTest.java
@@ -258,7 +258,7 @@
assertThat(TinyFrameworkEnumSimple.valueOf("DOG").ordinal()).isEqualTo(1);
assertThat(TinyFrameworkEnumSimple.values()).isEqualTo(
- new TinyFrameworkEnumSimple[] {
+ new TinyFrameworkEnumSimple[]{
TinyFrameworkEnumSimple.CAT,
TinyFrameworkEnumSimple.DOG,
}
@@ -278,11 +278,17 @@
assertThat(TinyFrameworkEnumComplex.valueOf("BLUE").ordinal()).isEqualTo(2);
assertThat(TinyFrameworkEnumComplex.values()).isEqualTo(
- new TinyFrameworkEnumComplex[] {
+ new TinyFrameworkEnumComplex[]{
TinyFrameworkEnumComplex.RED,
TinyFrameworkEnumComplex.GREEN,
TinyFrameworkEnumComplex.BLUE,
}
);
}
+
+ @Test
+ public void testAidlHeuristics() {
+ assertThat(IPretendingAidl.Stub.addOne(1)).isEqualTo(2);
+ assertThat(IPretendingAidl.Proxy.addTwo(1)).isEqualTo(3);
+ }
}
diff --git a/tools/hoststubgen/scripts/Android.bp b/tools/hoststubgen/scripts/Android.bp
index 5da805e..b1ba07e 100644
--- a/tools/hoststubgen/scripts/Android.bp
+++ b/tools/hoststubgen/scripts/Android.bp
@@ -18,9 +18,3 @@
tools: ["dump-jar"],
cmd: "$(location dump-jar) -s -o $(out) $(in)",
}
-
-sh_binary_host {
- name: "run-ravenwood-test",
- src: "run-ravenwood-test",
- visibility: ["//visibility:public"],
-}
diff --git a/tools/hoststubgen/scripts/run-all-tests.sh b/tools/hoststubgen/scripts/run-all-tests.sh
index 2dac089..82faa91 100755
--- a/tools/hoststubgen/scripts/run-all-tests.sh
+++ b/tools/hoststubgen/scripts/run-all-tests.sh
@@ -22,10 +22,10 @@
READY_TEST_MODULES=(
HostStubGenTest-framework-all-test-host-test
hoststubgen-test-tiny-test
+ CtsUtilTestCasesRavenwood
)
MUST_BUILD_MODULES=(
- run-ravenwood-test
"${NOT_READY_TEST_MODULES[*]}"
HostStubGenTest-framework-test
)
@@ -51,8 +51,6 @@
# run ./scripts/build-framework-hostside-jars-without-genrules.sh
# These tests should all pass.
-run-ravenwood-test ${READY_TEST_MODULES[*]}
-
-run atest CtsUtilTestCasesRavenwood
+run atest ${READY_TEST_MODULES[*]}
echo ""${0##*/}" finished, with no unexpected failures. Ready to submit!"
\ No newline at end of file
diff --git a/tools/hoststubgen/scripts/run-ravenwood-test b/tools/hoststubgen/scripts/run-ravenwood-test
deleted file mode 100755
index 9bbb859..0000000
--- a/tools/hoststubgen/scripts/run-ravenwood-test
+++ /dev/null
@@ -1,129 +0,0 @@
-#!/bin/bash
-# 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.
-
-set -e
-
-# Script to run a "Ravenwood" host side test.
-#
-# A proper way to run these tests is to use `atest`, but `atest` has a known issue of loading
-# unrelated jar files as the class path, so for now we use this script to run host side tests.
-
-# Copy (with some changes) some functions from ../common.sh, so this script can be used without it.
-
-m() {
- if (( $SKIP_BUILD )) ; then
- echo "Skipping build: $*" 1>&2
- return 0
- fi
- run ${ANDROID_BUILD_TOP}/build/soong/soong_ui.bash --make-mode "$@"
-}
-
-run() {
- echo "Running: $*" 1>&2
- "$@"
-}
-
-run_junit_test_jar() {
- local jar="$1"
- echo "Starting test: $jar ..."
- run cd "${jar%/*}"
-
- run ${JAVA:-java} $JAVA_OPTS \
- -cp $jar \
- org.junit.runner.JUnitCore \
- com.android.hoststubgen.hosthelper.HostTestSuite || return 1
- return 0
-}
-
-help() {
- cat <<'EOF'
-
- run-ravenwood-test -- Run Ravenwood host tests
-
- Usage:
- run-ravenwood-test [options] MODULE-NAME ...
-
- Options:
- -h: Help
- -t: Run test only, without building
- -b: Build only, without running
-
- Example:
- run-ravenwood-test HostStubGenTest-framework-test-host-test
-
-EOF
-}
-
-#-------------------------------------------------------------------------
-# Parse options
-#-------------------------------------------------------------------------
-build=0
-test=0
-
-while getopts "htb" opt; do
- case "$opt" in
- h) help; exit 0 ;;
- t)
- test=1
- ;;
- b)
- build=1
- ;;
- esac
-done
-shift $(($OPTIND - 1))
-
-# If neither -t nor -b is provided, then build and run./
-if (( ( $build + $test ) == 0 )) ; then
- build=1
- test=1
-fi
-
-
-modules=("${@}")
-
-if (( "${#modules[@]}" == 0 )); then
- help
- exit 1
-fi
-
-#-------------------------------------------------------------------------
-# Build
-#-------------------------------------------------------------------------
-if (( $build )) ; then
- run m "${modules[@]}"
-fi
-
-#-------------------------------------------------------------------------
-# Run
-#-------------------------------------------------------------------------
-
-failures=0
-if (( test )) ; then
- for module in "${modules[@]}"; do
- if run_junit_test_jar "$ANDROID_BUILD_TOP/out/host/linux-x86/testcases/${module}/${module}.jar"; then
- : # passed.
- else
- failures=$(( failures + 1 ))
- fi
- done
-
- if (( $failures > 0 )) ; then
- echo "$failures test jar(s) failed." 1>&2
- exit 2
- fi
-fi
-
-exit 0
\ No newline at end of file