diff options
152 files changed, 2215 insertions, 3311 deletions
diff --git a/cmds/gpu_counter_producer/Android.bp b/cmds/gpu_counter_producer/Android.bp index 2232345ce4fa..d645d066befd 100644 --- a/cmds/gpu_counter_producer/Android.bp +++ b/cmds/gpu_counter_producer/Android.bp @@ -19,6 +19,4 @@ cc_binary { "-Wunused", "-Wunreachable-code", ], - - soc_specific: true, } 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 000000000000..b89e2cdbd905 --- /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 4498bc2a09d6..5ec40e5d04e3 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 @@ public class Event { // 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 class Event { 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 @@ public class Event { 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 class Event { } public int getBus() { - return mBus.getValue(); + return mBusId; } public int[] getInjections() { @@ -168,7 +174,7 @@ public class Event { + ", name=" + mName + ", vid=" + mVid + ", pid=" + mPid - + ", bus=" + mBus + + ", busId=" + mBusId + ", events=" + Arrays.toString(mInjections) + ", configuration=" + mConfiguration + ", duration=" + mDurationMillis + "ms" @@ -218,8 +224,8 @@ public class Event { 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 000000000000..a4df03df7cd1 --- /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 a2195c7809be..888ec5a1d33a 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.Log; 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 @@ import src.com.android.commands.uinput.InputAbsInfo; /** * 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 @@ public class JsonStyleParser { 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 @@ public class JsonStyleParser { }); } - 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 fe76abb9861d..684a12fc8f37 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 @@ package com.android.commands.uinput; 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 @@ import java.util.Objects; 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 @@ public class Uinput { 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/core/java/android/hardware/location/NanoAppMessage.java b/core/java/android/hardware/location/NanoAppMessage.java index bb3e81ad0ec1..7ac1dd14da21 100644 --- a/core/java/android/hardware/location/NanoAppMessage.java +++ b/core/java/android/hardware/location/NanoAppMessage.java @@ -56,6 +56,8 @@ public final class NanoAppMessage implements Parcelable { * * @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/com/android/internal/pm/OWNERS b/core/java/com/android/internal/pm/OWNERS new file mode 100644 index 000000000000..6ef34e2e5d4b --- /dev/null +++ b/core/java/com/android/internal/pm/OWNERS @@ -0,0 +1,4 @@ +# Bug component: 36137 + +file:/PACKAGE_MANAGER_OWNERS + diff --git a/packages/PackageInstaller/AndroidManifest.xml b/packages/PackageInstaller/AndroidManifest.xml index 6e47689d585c..0d1c9b07bf55 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 4eaa39bcd3a4..0a2e8809a17c 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 000000000000..754437e64e78 --- /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 000000000000..6ccbc4cb5e6b --- /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 000000000000..3991f26e1b0c --- /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 000000000000..588168636828 --- /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/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java index f0e3c99b007d..643420989d1a 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 @@ public interface ActivityStarter { 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/src/com/android/keyguard/ActiveUnlockConfig.kt b/packages/SystemUI/src/com/android/keyguard/ActiveUnlockConfig.kt index 375727437b8b..1ee58deb501c 100644 --- a/packages/SystemUI/src/com/android/keyguard/ActiveUnlockConfig.kt +++ b/packages/SystemUI/src/com/android/keyguard/ActiveUnlockConfig.kt @@ -317,7 +317,7 @@ class ActiveUnlockConfig @Inject constructor( } keyguardUpdateMonitor?.let { - val anyFaceEnrolled = it.isFaceEnrolled + val anyFaceEnrolled = it.isFaceEnabledAndEnrolled val anyFingerprintEnrolled = it.isUnlockWithFingerprintPossible( selectedUserInteractor.getSelectedUserId()) val udfpsEnrolled = it.isUdfpsEnrolled @@ -372,7 +372,7 @@ class ActiveUnlockConfig @Inject constructor( 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 d7019b5c5d04..000000000000 --- 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 1b6112f52082..f706301df1ca 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java @@ -214,7 +214,6 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard public void onUserInput() { mBouncerMessageInteractor.onPrimaryBouncerUserInput(); mKeyguardFaceAuthInteractor.onPrimaryBouncerUserInput(); - mUpdateMonitor.cancelFaceAuth(); } @Override @@ -340,16 +339,11 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard 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 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard } 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 baab637a979c..c5bb0995f492 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.FACE; 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.BiometricSourceType; 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.telephony.TelephonyManager; 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.Background; 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.FaceDetectionStatus; 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 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab 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 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } } }; - 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 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab 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 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab 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 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab @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 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab 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 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab // 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 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab @VisibleForTesting protected final Runnable mFpCancelNotReceived = this::onFingerprintCancelNotReceived; - private final Runnable mFaceCancelNotReceived = this::onFaceCancelNotReceived; private final Provider<SessionTracker> mSessionTrackerProvider; @VisibleForTesting @@ -481,8 +405,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab 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 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab 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 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab // 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 class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab 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 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } } - 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 class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab */ public void onCameraLaunched() { mSecureCameraLaunched = true; - updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE, - FACE_AUTH_UPDATED_CAMERA_LAUNCHED); + updateFingerprintListeningState(BIOMETRIC_ACTION_UPDATE); } /** @@ -951,8 +848,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab // 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 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab mLogger.logFingerprintDetected(authUserId, isStrongBiometric); } else if (biometricSourceType == FACE) { mLogger.logFaceDetected(authUserId, isStrongBiometric); - setFaceRunningState(BIOMETRIC_STATE_STOPPED); } Trace.endSection(); @@ -1140,7 +1035,6 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab if (isUdfpsEnrolled()) { updateFingerprintListeningState(BIOMETRIC_ACTION_UPDATE); } - stopListeningForFace(FACE_AUTH_STOPPED_FP_LOCKED_OUT); } mLogger.logFingerprintError(msgId, errString); @@ -1218,16 +1112,11 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab 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 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab 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 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab "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 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab 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 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } } - /** - * @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 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } } - /** - * @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 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } } - if (lockedOutStateChanged) { - notifyLockedOutStateChanged(FACE); - } - if (mActiveUnlockConfig.shouldRequestActiveUnlockOnFaceError(msgId)) { requestActiveUnlock( ActiveUnlockConfig.ActiveUnlockRequestOrigin.BIOMETRIC_FAIL, @@ -1415,49 +1237,6 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } } - 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 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab */ @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 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab /** * 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 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } /** - * @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 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab 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 class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab */ 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 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab // 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 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab case FINGERPRINT: return isUnlockingWithBiometricAllowed(isFingerprintClass3()); case FACE: - return isUnlockingWithBiometricAllowed(isFaceClass3()); + return getFaceAuthInteractor() != null + && isUnlockingWithBiometricAllowed( + getFaceAuthInteractor().isFaceAuthStrong()); default: return false; } @@ -1757,14 +1543,9 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } } 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 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } } 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 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab 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 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } }; - 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 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab @Override public void onUdfpsPointerDown(int sensorId) { mLogger.logUdfpsPointerDown(sensorId); - requestFaceAuth(FaceAuthApiRequestReason.UDFPS_POINTER_DOWN); } /** @@ -2024,56 +1790,12 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } }; - 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 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab @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 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab 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 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab // 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 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab 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 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } } updateFingerprintListeningState(BIOMETRIC_ACTION_UPDATE); - if (mIsDreaming) { - updateFaceListeningState(BIOMETRIC_ACTION_STOP, FACE_AUTH_STOPPED_DREAM_STARTED); - } } private void handleUserUnlocked(int userId) { @@ -2344,7 +2048,6 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab @VisibleForTesting void resetBiometricListeningState() { mFingerprintRunningState = BIOMETRIC_STATE_STOPPED; - mFaceRunningState = BIOMETRIC_STATE_STOPPED; } @VisibleForTesting @@ -2376,17 +2079,14 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab 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 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab 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 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab .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 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab 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 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab }); 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 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab @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 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } }); 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 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } } - private boolean isFaceSupported() { - return mFaceManager != null && !mFaceSensorProperties.isEmpty(); - } - private boolean isFingerprintSupported() { return mFpm != null && !mFingerprintSensorProperties.isEmpty(); } @@ -2760,17 +2433,13 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } /** - * @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 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab 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 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab 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 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab @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 class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab 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 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab 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 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab /** * 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; - } - - private boolean doesPostureAllowFaceAuth(@DevicePostureInt int posture) { - return mConfigFaceAuthSupportedPosture == DEVICE_POSTURE_UNKNOWN - || (posture == mConfigFaceAuthSupportedPosture); + return getFaceAuthInteractor() != null && getFaceAuthInteractor().canFaceAuthRun(); } - /** - * 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 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab 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 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } } - 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 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab * @return {@code true} if possible. */ public boolean isUnlockingWithBiometricsPossible(int userId) { - return isUnlockWithFacePossible(userId) || isUnlockWithFingerprintPossible(userId); + return isUnlockWithFacePossible() || isUnlockWithFingerprintPossible(userId); } /** @@ -3455,8 +2894,12 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab * @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 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } /** - * @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 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } } - 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 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } } - // 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 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab @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 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab cb.onKeyguardBouncerFullyShowingChanged(mPrimaryBouncerFullyShown); } } - updateFaceListeningState(BIOMETRIC_ACTION_UPDATE, - FACE_AUTH_UPDATED_PRIMARY_BOUNCER_SHOWN); } } @@ -4071,8 +3482,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } 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 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab 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 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab 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 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab 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 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab mLockPatternUtils.unregisterStrongAuthTracker(mStrongAuthTracker); mTrustManager.unregisterTrustListener(this); - mDisplayTracker.removeCallback(mDisplayCallback); mHandler.removeCallbacksAndMessages(null); } @@ -4446,7 +3848,6 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab 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 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab 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 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab * 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 5bf8d635f8ee..055ca565a933 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.content.Intent 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 @@ constructor(@KeyguardUpdateMonitorLog private val logBuffer: LogBuffer) { 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 @@ constructor(@KeyguardUpdateMonitorLog private val logBuffer: LogBuffer) { ) } - 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 @@ constructor(@KeyguardUpdateMonitorLog private val logBuffer: LogBuffer) { 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 @@ constructor(@KeyguardUpdateMonitorLog private val logBuffer: LogBuffer) { 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 @@ constructor(@KeyguardUpdateMonitorLog private val logBuffer: LogBuffer) { 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 @@ constructor(@KeyguardUpdateMonitorLog private val logBuffer: LogBuffer) { ) } - 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 @@ constructor(@KeyguardUpdateMonitorLog private val logBuffer: LogBuffer) { ) } - 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 @@ constructor(@KeyguardUpdateMonitorLog private val logBuffer: LogBuffer) { ) } - 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 bbdcadbb19c6..cb750493ba26 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.content.res.Resources 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 @@ class FaceAuthAccessibilityDelegate @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 @@ constructor( 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 e15538b88d8c..85a119c389c1 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.R; 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; @@ -1013,9 +1012,6 @@ public class UdfpsController implements DozeReceiver, Dumpable { 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 35c3ded9e984..6954eb66cfa6 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.CoroutineScope 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 @@ open class UdfpsKeyguardViewControllerLegacy( 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 @@ open class UdfpsKeyguardViewControllerLegacy( 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 @@ open class UdfpsKeyguardViewControllerLegacy( 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 56dfa5ed337c..aa7758f9380f 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.Application 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 @@ constructor( 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 @@ constructor( /** 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/decor/FaceScanningProviderFactory.kt b/packages/SystemUI/src/com/android/systemui/decor/FaceScanningProviderFactory.kt index 31a5d37a4450..4bfc9484f733 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 @@ class FaceScanningProviderFactory @Inject constructor( } 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 83c16ae9ea78..6a0e88246027 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 @@ package com.android.systemui.flags 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 @@ import javax.inject.Inject 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 1710a9f9903e..b357b563f791 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 @@ object Flags { @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") diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index fe9865b2d1dd..53ec3dead6c5 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 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable, } 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 c4dfe9afeb2a..8ef26621362f 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.Flow 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 @@ import kotlinx.coroutines.withContext */ 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 @@ constructor( 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 @@ constructor( .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) - - // 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" - ) + 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" ) - .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 @@ constructor( 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 @@ constructor( } 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 c8cb9e6aa0dd..f4a74f03696c 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 javax.inject.Inject 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 @@ import kotlinx.coroutines.flow.emptyFlow */ @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 @@ class NoopDeviceEntryFaceAuthRepository @Inject constructor() : DeviceEntryFaceA 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 85b0f4fb864b..5ed70b526f1b 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 @@ interface KeyguardFaceAuthInteractor { /** 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 @@ interface KeyguardFaceAuthInteractor { /** 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 @@ interface KeyguardFaceAuthInteractor { fun onPrimaryBouncerUserInput() fun onAccessibilityAction() fun onWalletLaunched() + + /** Whether face auth is considered class 3 */ + fun isFaceAuthStrong(): Boolean } /** @@ -81,4 +83,10 @@ interface FaceAuthenticationListener { /** 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 949c940bdebc..91b671599eb0 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.Position 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 @@ class KeyguardInteractor 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 @@ constructor( /** 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 fbadde63a6b9..cd6ab31f3908 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 @@ class NoopKeyguardFaceAuthInteractor @Inject constructor() : KeyguardFaceAuthInt 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 2641846251cc..ae356cd94350 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.bouncer.domain.interactor.PrimaryBouncerInteractor 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.model.SelectionStatus 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 @@ constructor( @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 @@ constructor( 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 @@ constructor( 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 @@ constructor( 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 @@ constructor( 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 @@ constructor( } .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/viewmodel/KeyguardRootViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt index 315626b6fcae..b3c7d3790527 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.Flags.newAodTransition 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 @@ constructor( 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 c810786681f0..c06e9a443a7b 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.policy.SystemBarUtils; 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 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump // 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 e84bfc512eb5..dd194eaade9b 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.MetricsLogger; 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 @@ public class QuickSettingsController implements Dumpable { // 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 dd24ca78005f..08415cb5b0cb 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 @@ public class KeyguardIndicationController { 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 @@ public class KeyguardIndicationController { 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 747efe3fb2c9..933d0ab880bd 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 @@ enum class StatusBarMode { /** * 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 d1594ef2e404..04152123e42d 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 @@ import kotlinx.coroutines.flow.merge /** * 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 index 47994d92d22b..6429815bcb9f 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_SEMI_TRANSPARENT_STATUS_BA 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.LetterboxAppearanceCalculator 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 @@ import kotlinx.coroutines.flow.stateIn * 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 @@ interface StatusBarModeRepository { 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 @@ constructor( } } - override fun start() { + fun start() { commandQueue.addCallback(commandQueueCallback) } @@ -340,16 +334,7 @@ constructor( ) } -@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 000000000000..962cb0953f97 --- /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/shared/NotificationsLiveDataRefactor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/NotificationsLiveDataStoreRefactor.kt index 44387c225ef1..8fc7106ecada 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 @@ object NotificationsLiveDataStoreRefactor { */ @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/phone/ActivityStarterImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterImpl.kt index e1fba2eda1c4..7aa7976b8f92 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 @@ constructor( ) } - 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 645769cdd586..57d49b250883 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.NotificationLockscreenUserManager.P 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.StatusBarState; 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 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { 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 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { StatusBarInitializer statusBarInitializer, StatusBarWindowController statusBarWindowController, StatusBarWindowStateController statusBarWindowStateController, - StatusBarModeRepository statusBarModeRepository, + StatusBarModeRepositoryStore statusBarModeRepository, KeyguardUpdateMonitor keyguardUpdateMonitor, StatusBarSignalPolicy statusBarSignalPolicy, PulseExpansionHandler pulseExpansionHandler, @@ -900,7 +899,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { 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 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { 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 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { @Override public void hide() { - mStatusBarModeRepository.clearTransient(); + mStatusBarModeRepository.getDefaultDisplay().clearTransient(); } }); @@ -1657,7 +1657,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { if (mDemoModeController.isInDemoMode()) return; if (mStatusBarTransitions != null) { checkBarMode( - mStatusBarModeRepository.getStatusBarMode().getValue(), + mStatusBarModeRepository.getDefaultDisplay().getStatusBarMode().getValue(), mStatusBarWindowState, mStatusBarTransitions); } @@ -1668,7 +1668,8 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { /** 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 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { } } - /** - * 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 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { // 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 b0183d3fbd40..674f1698d2a3 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 @@ open class KeyguardBypassController : Dumpable, StackScrollAlgorithm.BypassContr 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 332984413dde..32b3ac2ad150 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.Sensor 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 @@ class KeyguardLiftController @Inject constructor( isListening = false updateListeningState() keyguardFaceAuthInteractor.onDeviceLifted() - keyguardUpdateMonitor.requestFaceAuth( - FaceAuthApiRequestReason.PICK_UP_GESTURE_TRIGGERED - ) keyguardUpdateMonitor.requestActiveUnlock( ActiveUnlockConfig.ActiveUnlockRequestOrigin.WAKE, "KeyguardLiftController") @@ -117,7 +113,8 @@ class KeyguardLiftController @Inject constructor( 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 index eba7fe09a8af..7c871e183740 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.statusbar.LetterboxDetails; 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 @@ import javax.inject.Named; * 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 @@ public class LightsOutNotifController extends ViewController<View> { private int mDisplayId; @Inject - LightsOutNotifController( + LegacyLightsOutNotifController( @Named(LIGHTS_OUT_NOTIF_VIEW) View lightsOutNotifView, WindowManager windowManager, NotifLiveDataStore notifDataStore, @@ -72,7 +73,12 @@ public class LightsOutNotifController extends ViewController<View> { 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 4d3e2ad4813a..eec617bf91d3 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.navigationbar.NavigationModeController; 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 @@ public class LightBarController implements 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 @@ public class LightBarController implements DarkIconDispatcher darkIconDispatcher, BatteryController batteryController, NavigationModeController navModeController, - StatusBarModeRepository statusBarModeRepository, + StatusBarModeRepositoryStore statusBarModeRepository, DumpManager dumpManager, DisplayTracker displayTracker) { mJavaAdapter = javaAdapter; @@ -146,7 +146,7 @@ public class LightBarController implements @Override public void start() { mJavaAdapter.alwaysCollectFlow( - mStatusBarModeRepository.getStatusBarAppearance(), + mStatusBarModeRepository.getDefaultDisplay().getStatusBarAppearance(), this::onStatusBarAppearanceChanged); } @@ -476,7 +476,7 @@ public class LightBarController implements 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 @@ public class LightBarController implements 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 274b50fd79fd..daadedb06187 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 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb } /** - * 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 000000000000..ed8b3e8922f3 --- /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 7adc08ca00c0..49880d4475da 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.dagger.qualifiers.Main; 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 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue 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 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue StatusBarLocationPublisher locationPublisher, NotificationIconAreaController notificationIconAreaController, ShadeExpansionStateManager shadeExpansionStateManager, - FeatureFlagsClassic featureFlags, StatusBarIconController statusBarIconController, DarkIconManager.Factory darkIconManagerFactory, CollapsedStatusBarViewModel collapsedStatusBarViewModel, @@ -258,7 +255,6 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue 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 0618abbf00d8..96faa359d43e 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 @@ package com.android.systemui.statusbar.phone.fragment.dagger; 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 @@ public interface StatusBarFragmentComponent { getBatteryMeterViewController().init(); getHeadsUpAppearanceController().init(); getPhoneStatusBarViewController().init(); - getLightsOutNotifController().init(); + if (!NotificationsLiveDataStoreRefactor.isEnabled()) { + getLegacyLightsOutNotifController().init(); + } getStatusBarDemoMode().init(); } @@ -101,7 +104,7 @@ public interface StatusBarFragmentComponent { /** */ @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 b0532ce1817b..0bdd1a5b4d5f 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.Application 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 @@ class OngoingCallController @Inject constructor( 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 @@ class OngoingCallController @Inject constructor( 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 da9c45ad5ada..9c78ab42a14a 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 @@ import kotlinx.coroutines.flow.asStateFlow * * 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 b9b88f4b762c..7d7f49bb8d17 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 @@ class CollapsedStatusBarViewBinderImpl @Inject constructor() : CollapsedStatusBa 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 15ab143a7aeb..52a6d8cf0952 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.SysUISingleton 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 @@ interface CollapsedStatusBarViewModel { /** 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 @@ constructor( 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/KeyguardStateController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateController.java index 52133ee5b7cd..ad2b070788f2 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 @@ public interface KeyguardStateController extends CallbackController<Callback> { /** * If there are faces enrolled and user enabled face auth on keyguard. */ - default boolean isFaceEnrolled() { + default boolean isFaceEnrolledAndEnabled() { return false; } @@ -265,7 +265,7 @@ public interface KeyguardStateController extends CallbackController<Callback> { /** * 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 8cc7e7d21fc2..3deb9e7414af 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 @@ public class KeyguardStateControllerImpl implements KeyguardStateController, Dum 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 @@ public class KeyguardStateControllerImpl implements KeyguardStateController, Dum || (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 @@ public class KeyguardStateControllerImpl implements KeyguardStateController, Dum } @Override - public boolean isFaceEnrolled() { - return mFaceEnrolled; + public boolean isFaceEnrolledAndEnabled() { + return mFaceEnrolledAndEnabled; } @Override @@ -416,7 +416,7 @@ public class KeyguardStateControllerImpl implements KeyguardStateController, Dum 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/user/data/repository/UserRepository.kt b/packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepository.kt index 5fc435aae67f..cf76c0d2e696 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.SysUISingleton 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 @@ constructor( @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 d65a69c62072..9ee3d220a79b 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 androidx.lifecycle.Observer; 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 @@ import javax.inject.Inject; @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 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa 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 2132904caa84..5558aa72bb57 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 @@ public class WalletActivity extends ComponentActivity implements 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 e429446f66cf..3f76d303898e 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 @@ class ActiveUnlockConfigTest : SysuiTestCase() { // 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 @@ class ActiveUnlockConfigTest : SysuiTestCase() { // 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 @@ class ActiveUnlockConfigTest : SysuiTestCase() { ) // 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 @@ class ActiveUnlockConfigTest : SysuiTestCase() { ) // 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 2e9b7e84344b..b403d1d5fbdc 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 @@ class ClockEventControllerTest : SysuiTestCase() { 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 7feab9141da2..adf0adabe24c 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 @@ package com.android.keyguard; 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 @@ public class KeyguardClockSwitchControllerBaseTest extends SysuiTestCase { 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 225f12536a33..543b2910bbda 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.classifier.FalsingCollector 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 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() { @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 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() { telephonyManager, viewMediatorCallback, audioManager, - mock(), + faceAuthInteractor, mock(), { JavaAdapter(sceneTestUtils.testScope.backgroundScope) }, mSelectedUserInteractor, @@ -576,49 +578,12 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() { } @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 2b41e08065d1..1ab634c46de9 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.FINGERPR 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.BiometricManager; 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.test.suitebuilder.annotation.SmallTest; 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.AuthController; 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 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { 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 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { @Mock private FingerprintManager mFingerprintManager; @Mock - private FaceManager mFaceManager; - @Mock private BiometricManager mBiometricManager; @Mock private PackageManager mPackageManager; @@ -277,19 +258,18 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { @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 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { 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 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { 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 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { } 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 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { .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 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { 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 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { } @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 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { } @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 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { @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 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { } @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 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { } @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 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { } @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 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { @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 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { 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 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { } @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 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { @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 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { 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 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { 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 class KeyguardUpdateMonitorTest extends SysuiTestCase { 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 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { } @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 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { } @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 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { } @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 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { } @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 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { } @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 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { 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 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { } @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 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { } @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 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { // 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 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { } @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 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { // 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 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { } @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 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { // 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 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { } @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 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { } @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 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { } @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 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { } @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 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { @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 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { } @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 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { } @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 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { 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); - 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); + 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 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 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { 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 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { } 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 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { 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 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { 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 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { 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 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { 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 d2f45ae8685a..3d7d701ee5d6 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 @@ package com.android.keyguard; 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 @@ public class LockIconViewControllerBaseTest extends SysuiTestCase { 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 ea7cc3dcd119..6c91c987f327 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 @@ class FaceScanningProviderFactoryTest : SysuiTestCase() { @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 @@ class FaceScanningProviderFactoryTest : SysuiTestCase() { @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 @@ class FaceScanningProviderFactoryTest : SysuiTestCase() { @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 00ea78f01fa9..993dbac747e8 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 @@ class AuthDialogPanelInteractionDetectorTest : SysuiTestCase() { .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 ec17794d4ee2..86b9b84ab36e 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.View 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 @@ import org.mockito.MockitoAnnotations @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 @@ class FaceAuthAccessibilityDelegateTest : SysuiTestCase() { 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 @@ class FaceAuthAccessibilityDelegateTest : SysuiTestCase() { @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 @@ class FaceAuthAccessibilityDelegateTest : SysuiTestCase() { @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 @@ class FaceAuthAccessibilityDelegateTest : SysuiTestCase() { 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 9bff88bbf2dd..79f062536404 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.DismissCallbackRegistry 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 @@ class UdfpsKeyguardViewLegacyControllerWithCoroutinesTest : FakeTrustRepository(), testScope.backgroundScope, mSelectedUserInteractor, + mock(KeyguardFaceAuthInteractor::class.java), ) mAlternateBouncerInteractor = AlternateBouncerInteractor( 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 b48bc1d28f86..094616f0682c 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.FakeBiometricSettingsReposi 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.junit.runner.RunWith 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 @@ class BouncerMessageInteractorTest : SysuiTestCase() { 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 d6aa9ac87d39..37a093e4c23f 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.bouncer.ui.BouncerViewDelegate 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 @@ class PrimaryBouncerInteractorTest : SysuiTestCase() { @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 @@ class PrimaryBouncerInteractorTest : SysuiTestCase() { trustRepository, testScope.backgroundScope, mSelectedUserInteractor, + faceAuthInteractor, ) whenever(repository.primaryBouncerStartingDisappearAnimation.value).thenReturn(null) whenever(repository.primaryBouncerShow.value).thenReturn(false) @@ -423,10 +425,7 @@ class PrimaryBouncerInteractorTest : SysuiTestCase() { 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 @@ class PrimaryBouncerInteractorTest : SysuiTestCase() { } @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 d1b120e0948b..bdf5041f8a38 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.classifier.FalsingCollector 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 @@ class PrimaryBouncerInteractorWithCoroutinesTest : SysuiTestCase() { @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 @@ class PrimaryBouncerInteractorWithCoroutinesTest : SysuiTestCase() { 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 2cc8f0a47955..90e0c19b7c65 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.collectLastValue 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 @@ class KeyguardBouncerViewModelTest : SysuiTestCase() { @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 @@ class KeyguardBouncerViewModelTest : SysuiTestCase() { 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 6c990e457209..40c9432d543d 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.testing.TestableLooper 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.KeyguardPreviewRenderer 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 @@ class CustomizationProviderTest : SysuiTestCase() { 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 f0ff77ebf1ea..852f9a540221 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 @@ class ResourceTrimmerTest : SysuiTestCase() { 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 0b148d14a43f..45aca175657e 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.display.data.repository.display 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 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() { 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 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() { } @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 f2de8caef176..b3e8fed24c3b 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.bouncer.ui.BouncerView 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 @@ class KeyguardFaceAuthInteractorTest : SysuiTestCase() { 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 @@ class KeyguardFaceAuthInteractorTest : SysuiTestCase() { 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 @@ class KeyguardFaceAuthInteractorTest : SysuiTestCase() { 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 ad2ec72468ad..706f94e412ac 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.SysuiTestCase 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 @@ class KeyguardInteractorTest : SysuiTestCase() { 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 @@ class KeyguardInteractorTest : SysuiTestCase() { 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 fe474faa877d..66c8a229f0a1 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.ContentDescription 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 @@ class KeyguardQuickAffordanceInteractorParameterizedTest : SysuiTestCase() { 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 @@ class KeyguardQuickAffordanceInteractorParameterizedTest : SysuiTestCase() { } 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 347d580abf5b..bc4bae0ed959 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 android.os.UserHandle 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.coroutines.collectLastValue 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.ActivationState 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 @@ class KeyguardQuickAffordanceInteractorTest : SysuiTestCase() { 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 @@ class KeyguardQuickAffordanceInteractorTest : SysuiTestCase() { dumpManager = mock(), userHandle = UserHandle.SYSTEM, ) - featureFlags = - FakeFeatureFlags().apply { - set(Flags.FACE_AUTH_REFACTOR, true) - } + featureFlags = FakeFeatureFlags() val withDeps = KeyguardInteractorFactory.create( @@ -216,9 +214,8 @@ class KeyguardQuickAffordanceInteractorTest : SysuiTestCase() { 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 @@ class KeyguardQuickAffordanceInteractorTest : SysuiTestCase() { 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 @@ class KeyguardQuickAffordanceInteractorTest : SysuiTestCase() { 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 bf23bf875ad3..bf6d5c4535ec 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 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() { 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 91e17059bb3d..1f245f1e86f0 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.bouncer.domain.interactor.PrimaryBouncerInteractor 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 @@ class OccludingAppDeviceEntryInteractorTest : SysuiTestCase() { 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 @@ class OccludingAppDeviceEntryInteractorTest : SysuiTestCase() { 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 16d072e99964..87eee1a8d817 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.bouncer.data.repository.KeyguardBouncerRepository 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 @@ class UdfpsKeyguardInteractorTest : SysuiTestCase() { 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 @@ class UdfpsKeyguardInteractorTest : SysuiTestCase() { 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/viewmodel/KeyguardBottomAreaViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt index 32d28a3d7bb2..1584be0ab565 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 android.os.UserHandle 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.ActivationState 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 @@ class KeyguardBottomAreaViewModelTest : SysuiTestCase() { 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 @@ class KeyguardBottomAreaViewModelTest : SysuiTestCase() { 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 25d141997734..67c4e2688cd0 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.content.Intent 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.ActivationState 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 @@ class KeyguardQuickAffordancesCombinedViewModelTest : SysuiTestCase() { 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 a838684a4f41..e6d6cf263d69 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.common.ui.data.repository.FakeConfigurationRepositor 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 @@ class KeyguardRootViewModelTest : SysuiTestCase() { 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 @@ class KeyguardRootViewModelTest : SysuiTestCase() { deviceEntryInteractor = mock { whenever(isBypassEnabled).thenReturn(MutableStateFlow(false)) }, dozeParameters = mock(), - featureFlags, keyguardInteractor, keyguardTransitionInteractor, notificationsKeyguardInteractor = @@ -347,8 +342,7 @@ class KeyguardRootViewModelTestWithFakes : SysuiTestCase() { 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 c50be04e8a9c..2314c8358ff8 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.collectValues 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 @@ class LockscreenToAodTransitionViewModelTest : SysuiTestCase() { .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 26704da1496f..baac51385ba1 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 @@ class LockscreenToDreamingTransitionViewModelTest : SysuiTestCase() { .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 ff3135a6ad98..29d8f082795a 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 @@ class LockscreenToOccludedTransitionViewModelTest : SysuiTestCase() { .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 8afd8e4fd425..049e4e27e374 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 @@ class LockscreenToPrimaryBouncerTransitionViewModelTest : SysuiTestCase() { .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 5058b1686781..6512290bf556 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.bouncer.data.repository.KeyguardBouncerRepository 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 @@ class UdfpsAodViewModelTest : SysuiTestCase() { 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 @@ class UdfpsAodViewModelTest : SysuiTestCase() { 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 f039f5302a3f..95b2fe554f0c 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.bouncer.data.repository.KeyguardBouncerRepository 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 @@ class UdfpsFingerprintViewModelTest : SysuiTestCase() { 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 @@ class UdfpsFingerprintViewModelTest : SysuiTestCase() { 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 c1805dbf26ad..848a94b2a5d2 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.SysuiTestCase 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 @@ class UdfpsLockscreenViewModelTest : SysuiTestCase() { 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 @@ class UdfpsLockscreenViewModelTest : SysuiTestCase() { 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 722fb2c75081..36b4435e2137 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.any; 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 android.view.accessibility.AccessibilityNodeInfo; 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 @@ public class NotificationPanelViewControllerTest extends NotificationPanelViewCo 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 8403ac59d2f5..39b306b781f9 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 @@ public class NotificationShadeWindowControllerImplTest extends SysuiTestCase { 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 d89491c7b442..0587633b09cf 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.FakeBiometricSettingsReposi 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.any 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.mock 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 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() { 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 9c8816c72fae..29b1366eb6c1 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 @@ class NotificationShadeWindowViewTest : SysuiTestCase() { 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 bff47f1e3927..1dbb2972c6f3 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 @@ public class QuickSettingsControllerBaseTest extends SysuiTestCase { 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 61e4370949ca..65e0fa146fe3 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 @@ class ShadeInteractorImplTest : SysuiTestCase() { .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 92eb6ed52c14..6e6e4384b7b3 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 @@ class ShadeInteractorLegacyImplTest : SysuiTestCase() { .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 729f3f840e1a..565e20a034db 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 @@ class ShadeInteractorSceneContainerImplTest : SysuiTestCase() { .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 63e46d1895bd..459040abd566 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 @@ package com.android.systemui.statusbar; 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.internal.widget.LockPatternUtils; 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.domain.interactor.KeyguardInteractorFactory 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 @@ public class KeyguardIndicationControllerBaseTest extends SysuiTestCase { 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 dd3ac927ebdf..aa53558e858d 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 @@ public class KeyguardIndicationControllerTest extends KeyguardIndicationControll 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 @@ public class KeyguardIndicationControllerTest extends KeyguardIndicationControll 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 @@ public class KeyguardIndicationControllerTest extends KeyguardIndicationControll 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 8fa7cd291851..7546dfa1cbf9 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.Mock 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 @@ class StatusBarStateControllerImplTest : SysuiTestCase() { whenever(interactionJankMonitor.end(anyInt())).thenReturn(true) uiEventLogger = UiEventLoggerFake() - controller = object : StatusBarStateControllerImpl( - uiEventLogger, - interactionJankMonitor, - mock(), - { shadeInteractor } - ) { - override fun createDarkAnimator(): ObjectAnimator { return mockDarkAnimator } - } - - val powerInteractor = PowerInteractor( - FakePowerRepository(), - FalsingCollectorFake(), - mock(), - controller) + controller = + object : + StatusBarStateControllerImpl( + uiEventLogger, + interactionJankMonitor, + mock(), + { shadeInteractor } + ) { + override fun createDarkAnimator(): ObjectAnimator { + return mockDarkAnimator + } + } + + 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 d1a46fca21c8..057dcb2a156e 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 @@ class StatusBarModeRepositoryImplTest : SysuiTestCase() { 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 10d4c627bc4a..b3fc25c47912 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 @@ class NotificationIconContainerAlwaysOnDisplayViewModelTest : SysuiTestCase() { 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 e264fc07489a..741564505b53 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 @@ class NotificationIconContainerStatusBarViewModelTest : SysuiTestCase() { 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/phone/BiometricsUnlockControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java index e61b4f81aaee..051a4c1c05cd 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 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase { 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/KeyguardBypassControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBypassControllerTest.kt index bd0dbeebd752..91cbc3274900 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 @@ class KeyguardBypassControllerTest : SysuiTestCase() { 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 361df1c63ffd..62a2bc54af20 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.flags.Flags; 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 @@ public class KeyguardStatusBarViewControllerTest extends SysuiTestCase { 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 index 287ebba4db24..bde2243db4e6 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 @@ import java.util.Objects; @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 @@ public class LightsOutNotifControllerTest extends SysuiTestCase { @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 @@ public class LightsOutNotifControllerTest extends SysuiTestCase { 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 c45ecf3fe225..f6419a9c4784 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 @@ public class LightBarControllerTest extends SysuiTestCase { 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 @@ public class LightBarControllerTest extends SysuiTestCase { new AppearanceRegion(0 /* appearance */, secondBounds) ); - mStatusBarModeRepository.getStatusBarAppearance().setValue( + mStatusBarModeRepository.getDefaultDisplay().getStatusBarAppearance().setValue( new StatusBarAppearance( StatusBarMode.TRANSPARENT, STATUS_BAR_BOUNDS, @@ -165,7 +165,7 @@ public class LightBarControllerTest extends SysuiTestCase { 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 @@ public class LightBarControllerTest extends SysuiTestCase { 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 @@ public class LightBarControllerTest extends SysuiTestCase { new AppearanceRegion(0 /* appearance */, secondBounds) ); - mStatusBarModeRepository.getStatusBarAppearance().setValue( + mStatusBarModeRepository.getDefaultDisplay().getStatusBarAppearance().setValue( new StatusBarAppearance( StatusBarMode.TRANSPARENT, STATUS_BAR_BOUNDS, @@ -231,7 +231,7 @@ public class LightBarControllerTest extends SysuiTestCase { 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 @@ public class LightBarControllerTest extends SysuiTestCase { 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 @@ public class LightBarControllerTest extends SysuiTestCase { 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 @@ public class LightBarControllerTest extends SysuiTestCase { 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 @@ public class LightBarControllerTest extends SysuiTestCase { /* 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 @@ public class LightBarControllerTest extends SysuiTestCase { 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 000000000000..5a0e13d02b92 --- /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 0b87fe8da184..17c29382b39a 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.animation.AnimatorTestRule; 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 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest { 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 49de5125cb4d..7b73528cd932 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 @@ class OngoingCallControllerTest : SysuiTestCase() { @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 @@ class OngoingCallControllerTest : SysuiTestCase() { @Test fun callStartedInImmersiveMode_swipeGestureCallbackAdded() { - statusBarModeRepository.isInFullscreenMode.value = true + statusBarModeRepository.defaultDisplay.isInFullscreenMode.value = true testScope.runCurrent() notifCollectionListener.onEntryUpdated(createOngoingCallNotifEntry()) @@ -570,7 +570,7 @@ class OngoingCallControllerTest : SysuiTestCase() { @Test fun callStartedNotInImmersiveMode_swipeGestureCallbackNotAdded() { - statusBarModeRepository.isInFullscreenMode.value = false + statusBarModeRepository.defaultDisplay.isInFullscreenMode.value = false testScope.runCurrent() notifCollectionListener.onEntryUpdated(createOngoingCallNotifEntry()) @@ -583,7 +583,7 @@ class OngoingCallControllerTest : SysuiTestCase() { fun transitionToImmersiveMode_swipeGestureCallbackAdded() { notifCollectionListener.onEntryUpdated(createOngoingCallNotifEntry()) - statusBarModeRepository.isInFullscreenMode.value = true + statusBarModeRepository.defaultDisplay.isInFullscreenMode.value = true testScope.runCurrent() verify(mockSwipeStatusBarAwayGestureHandler) @@ -592,11 +592,11 @@ class OngoingCallControllerTest : SysuiTestCase() { @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 @@ class OngoingCallControllerTest : SysuiTestCase() { @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 688f739f61f8..09dc1e537e9f 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 + + @Component.Factory + interface Factory { + fun create( + @BindsInstance test: SysuiTestCase, + testScope: CoroutineTestScopeModule, + ): TestComponent + } + } - private lateinit var keyguardTransitionRepository: FakeKeyguardTransitionRepository - private lateinit var testScope: TestScope + @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 @@ class CollapsedStatusBarViewModelImplTest : SysuiTestCase() { @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 @@ class CollapsedStatusBarViewModelImplTest : SysuiTestCase() { @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 @@ class CollapsedStatusBarViewModelImplTest : SysuiTestCase() { @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 @@ class CollapsedStatusBarViewModelImplTest : SysuiTestCase() { @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 @@ class CollapsedStatusBarViewModelImplTest : SysuiTestCase() { @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 @@ class CollapsedStatusBarViewModelImplTest : SysuiTestCase() { @Test fun transitionFromLockscreenToDreamStartedEvent_started_emitted() = - testScope.runTest { + testComponent.runTest { val emissions by collectValues(underTest.transitionFromLockscreenToDreamStartedEvent) keyguardTransitionRepository.sendTransitionStep( @@ -199,7 +227,7 @@ class CollapsedStatusBarViewModelImplTest : SysuiTestCase() { @Test fun transitionFromLockscreenToDreamStartedEvent_startedMultiple_emittedMultiple() = - testScope.runTest { + testComponent.runTest { val emissions by collectValues(underTest.transitionFromLockscreenToDreamStartedEvent) keyguardTransitionRepository.sendTransitionStep( @@ -234,7 +262,7 @@ class CollapsedStatusBarViewModelImplTest : SysuiTestCase() { @Test fun transitionFromLockscreenToDreamStartedEvent_startedThenRunning_emittedOnlyOne() = - testScope.runTest { + testComponent.runTest { val emissions by collectValues(underTest.transitionFromLockscreenToDreamStartedEvent) keyguardTransitionRepository.sendTransitionStep( @@ -283,7 +311,7 @@ class CollapsedStatusBarViewModelImplTest : SysuiTestCase() { @Test fun transitionFromLockscreenToDreamStartedEvent_irrelevantTransition_notEmitted() = - testScope.runTest { + testComponent.runTest { val emissions by collectValues(underTest.transitionFromLockscreenToDreamStartedEvent) keyguardTransitionRepository.sendTransitionStep( @@ -300,7 +328,7 @@ class CollapsedStatusBarViewModelImplTest : SysuiTestCase() { @Test fun transitionFromLockscreenToDreamStartedEvent_irrelevantTransitionState_notEmitted() = - testScope.runTest { + testComponent.runTest { val emissions by collectValues(underTest.transitionFromLockscreenToDreamStartedEvent) keyguardTransitionRepository.sendTransitionStep( @@ -317,4 +345,65 @@ class CollapsedStatusBarViewModelImplTest : SysuiTestCase() { 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 88587b2db0f9..bc50f7967403 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/KeyguardStateControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardStateControllerTest.java index 5c960b6633db..01dad381efa0 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 class KeyguardStateControllerTest extends SysuiTestCase { 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 96db09edaf88..59bf9f30a828 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.SysuiTestCase 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 @@ class KeyguardStatusBarViewModelTest : SysuiTestCase() { 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 7f990a446aaf..f9241343549c 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 androidx.test.filters.SmallTest 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 @@ class FoldAodAnimationControllerTest : SysuiTestCase() { 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 0d78ae9c7b11..abfff34f6dba 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.os.UserManager 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 @@ class UserRepositoryImplTest : SysuiTestCase() { } 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 @@ class UserRepositoryImplTest : SysuiTestCase() { 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 017eefe38f2a..bf851eb69a0d 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 @@ class UserSwitcherInteractorTest : SysuiTestCase() { ) 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 7041eab9d247..d1870b1d8fcd 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 @@ class StatusBarUserChipViewModelTest : SysuiTestCase() { } 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 686f492fde50..b7b24f6dc7dd 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 @@ class UserSwitcherViewModelTest : SysuiTestCase() { 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 200cfd3605c3..ca167ad3cd14 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java @@ -415,7 +415,6 @@ public class BubblesTest extends SysuiTestCase { 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 df31a12b8415..1381464c6ad1 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 @@ class FakeBiometricSettingsRepository @Inject constructor() : BiometricSettingsR 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 6c2ce7139375..3d8ae1e9801a 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 @@ object KeyguardDismissInteractorFactory { 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 d2ff9bc5f3eb..c575bb3fe25d 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 @@ package com.android.systemui.keyguard.domain.interactor 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 @@ object KeyguardInteractorFactory { @JvmOverloads @JvmStatic fun create( - featureFlags: FakeFeatureFlags = createFakeFeatureFlags(), + featureFlags: FakeFeatureFlags = FakeFeatureFlags(), sceneContainerFlags: SceneContainerFlags = FakeSceneContainerFlags(), repository: FakeKeyguardRepository = FakeKeyguardRepository(), commandQueue: FakeCommandQueue = FakeCommandQueue(), @@ -62,7 +61,6 @@ object KeyguardInteractorFactory { KeyguardInteractor( repository = repository, commandQueue = commandQueue, - featureFlags = featureFlags, sceneContainerFlags = sceneContainerFlags, bouncerRepository = bouncerRepository, configurationRepository = configurationRepository, @@ -73,11 +71,6 @@ object KeyguardInteractorFactory { ) } - /** 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 4843ae7ceb1d..bb840362185f 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 @@ package com.android.systemui.keyguard.domain.interactor 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 @@ val Kosmos.keyguardInteractor by 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 80c38b2d228c..3c96051a718f 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 @@ class SceneTestUtils( 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 @@ class SceneTestUtils( 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 f25d282208f0..60690838fcdf 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 @@ class FakeStatusBarModeRepository @Inject constructor() : StatusBarModeRepositor @Module interface FakeStatusBarModeRepositoryModule { - @Binds fun bindFake(fake: FakeStatusBarModeRepository): StatusBarModeRepository + @Binds fun bindFake(fake: FakeStatusBarModeRepository): StatusBarModeRepositoryStore } diff --git a/services/core/java/com/android/server/audio/SpatializerHelper.java b/services/core/java/com/android/server/audio/SpatializerHelper.java index ea92154f2df0..61e4f36a34ed 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 @@ package com.android.server.audio; 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 @@ public class SpatializerHelper { } 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 @@ public class SpatializerHelper { 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. } - break; } - if (uuid.equals(UuidUtils.STANDALONE_UUID)) { - headHandle = sensor.getHandle(); - // 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 (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/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 0492f4314875..c2b59644ce1c 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.AssociationRequest; 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 @@ public class NotificationManagerService extends SystemService { * 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); diff --git a/services/core/java/com/android/server/pm/PackageArchiver.java b/services/core/java/com/android/server/pm/PackageArchiver.java index d2a4c2713097..968be5c2cf1c 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 @@ public class PackageArchiver { 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 @@ public class PackageArchiver { 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 @@ public class PackageArchiver { } 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 @@ public class PackageArchiver { 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 @@ public class PackageArchiver { () -> 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 @@ public class PackageArchiver { } 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 @@ public class PackageArchiver { 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 @@ public class PackageArchiver { 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 f992bd83a8de..fc662038d5d5 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 @@ class PackageManagerShellCommand extends ShellCommand { 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/tests/mockingservicestests/src/com/android/server/pm/PackageArchiverTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/PackageArchiverTest.java index 18a2accf071d..733a43329478 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 android.text.TextUtils; 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.io.IOException; import java.nio.file.Path; import java.util.ArrayList; import java.util.List; +import java.util.Set; @SmallTest @Presubmit @@ -114,6 +116,8 @@ public class PackageArchiverTest { @Mock private PackageStateInternal mPackageState; @Mock + private PackageStateInternal mCallerPackageState; + @Mock private Bitmap mIcon; private final InstallSource mInstallSource = @@ -155,6 +159,11 @@ public class PackageArchiverTest { 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/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 b44f1a607b05..c49f8fecfdee 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.junit.FlickerParametersRunnerFactory 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 @@ class CloseImeToHomeOnFinishActivityTest(flicker: LegacyFlickerTest) : BaseTest( 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 976ac82c8bb5..994edc592f5d 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 android.tools.device.helpers.WindowUtils 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 @@ class OpenImeWindowToFixedPortraitAppTest(flicker: LegacyFlickerTest) : BaseTest // 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 05babd67758c..b7a183d7f7fe 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.junit.FlickerParametersRunnerFactory 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 @@ class ShowImeOnAppStartWhenLaunchingAppFromOverviewTest(flicker: LegacyFlickerTe /** {@inheritDoc} */ override val transition: FlickerBuilder.() -> Unit = { setup { + tapl.expectedRotationCheckEnabled = false tapl.workspace.switchToOverview().dismissAllTasks() testApp.launchViaIntent(wmHelper) testApp.openIME(wmHelper) @@ -54,7 +54,7 @@ class ShowImeOnAppStartWhenLaunchingAppFromOverviewTest(flicker: LegacyFlickerTe 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 aff8e657bec0..6ee5a9a775b3 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 @@ class ShowImeOnAppStartWhenLaunchingAppFromQuickSwitchTest(flicker: LegacyFlicke @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 4ffdcea455ba..1ad5c0de282b 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 @@ class ShowImeOnAppStartWhenLaunchingAppTest(flicker: LegacyFlickerTest) : BaseTe } 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 6ad235ce892e..181a2a229940 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.junit.FlickerParametersRunnerFactory 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 @@ class ShowImeWhileDismissingThemedPopupDialogTest(flicker: LegacyFlickerTest) : 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 7c9c05d7da85..ad272a052220 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 @@ constructor( /** 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 252f7d3e1bed..cb1aab0bfeea 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 @@ constructor( waitIMEShown(wmHelper) } - protected fun waitIMEShown(wmHelper: WindowManagerStateHelper) { + fun waitIMEShown(wmHelper: WindowManagerStateHelper) { wmHelper.StateSyncBuilder().withImeShown().waitForAndVerify() } @@ -63,17 +63,4 @@ constructor( 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 d3cee645cd99..0ee7aeeb30c6 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 @@ constructor( 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 @@ constructor( } 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 fa73e2c63780..507c1b622613 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 8b334c0a8588..80c1dd072df7 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 class ActivityOptions { 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 d7ee2af44111..4418b5a5ff82 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 @@ public class ImeActivity extends Activity { .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 7ee8debddcf1..cd711f72d8fd 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(); } } |