Merge "[PM] Add doRestore check and write pendingRestore" into main
diff --git a/Ravenwood.bp b/Ravenwood.bp
index 7c7c0e2..74382a6 100644
--- a/Ravenwood.bp
+++ b/Ravenwood.bp
@@ -34,6 +34,7 @@
"--debug-log $(location hoststubgen_framework-minus-apex.log) " +
"--stats-file $(location hoststubgen_framework-minus-apex_stats.csv) " +
+ "--supported-api-list-file $(location hoststubgen_framework-minus-apex_apis.csv) " +
"--out-impl-jar $(location ravenwood.jar) " +
@@ -58,6 +59,7 @@
"hoststubgen_framework-minus-apex.log",
"hoststubgen_framework-minus-apex_stats.csv",
+ "hoststubgen_framework-minus-apex_apis.csv",
],
visibility: ["//visibility:private"],
}
@@ -90,6 +92,18 @@
],
}
+genrule {
+ name: "framework-minus-apex.ravenwood.apis",
+ defaults: ["ravenwood-internal-only-visibility-genrule"],
+ cmd: "cp $(in) $(out)",
+ srcs: [
+ ":framework-minus-apex.ravenwood-base{hoststubgen_framework-minus-apex_apis.csv}",
+ ],
+ out: [
+ "hoststubgen_framework-minus-apex_apis.csv",
+ ],
+}
+
java_library {
name: "services.core-for-hoststubgen",
installable: false, // host only jar.
@@ -108,6 +122,7 @@
"--debug-log $(location hoststubgen_services.core.log) " +
"--stats-file $(location hoststubgen_services.core_stats.csv) " +
+ "--supported-api-list-file $(location hoststubgen_services.core_apis.csv) " +
"--out-impl-jar $(location ravenwood.jar) " +
@@ -132,6 +147,7 @@
"hoststubgen_services.core.log",
"hoststubgen_services.core_stats.csv",
+ "hoststubgen_services.core_apis.csv",
],
visibility: ["//visibility:private"],
}
@@ -161,6 +177,18 @@
],
}
+genrule {
+ name: "services.core.ravenwood.apis",
+ defaults: ["ravenwood-internal-only-visibility-genrule"],
+ cmd: "cp $(in) $(out)",
+ srcs: [
+ ":services.core.ravenwood-base{hoststubgen_services.core_apis.csv}",
+ ],
+ out: [
+ "hoststubgen_services.core_apis.csv",
+ ],
+}
+
java_library {
name: "services.core.ravenwood-jarjar",
installable: false,
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/UserWakeupStore.java b/apex/jobscheduler/service/java/com/android/server/alarm/UserWakeupStore.java
index a0d9133..7fc630c 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/UserWakeupStore.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/UserWakeupStore.java
@@ -136,10 +136,9 @@
* Remove wakeup scheduled for the user with given userId if present.
*/
public void removeUserWakeup(int userId) {
- synchronized (mUserWakeupLock) {
- mUserStarts.delete(userId);
+ if (deleteWakeupFromUserStarts(userId)) {
+ updateUserListFile();
}
- updateUserListFile();
}
/**
@@ -186,7 +185,7 @@
* Return scheduled start time for user or -1 if user does not have alarm set.
*/
@VisibleForTesting
- long getWakeupTimeForUserForTest(int userId) {
+ long getWakeupTimeForUser(int userId) {
synchronized (mUserWakeupLock) {
return mUserStarts.get(userId, -1);
}
@@ -197,8 +196,11 @@
*/
public void onUserStarting(int userId) {
synchronized (mUserWakeupLock) {
- mStartingUsers.put(userId, getWakeupTimeForUserForTest(userId));
- mUserStarts.delete(userId);
+ final long wakeup = getWakeupTimeForUser(userId);
+ if (wakeup >= 0) {
+ mStartingUsers.put(userId, wakeup);
+ mUserStarts.delete(userId);
+ }
}
}
@@ -206,21 +208,48 @@
* Remove userId from starting user list once start is complete.
*/
public void onUserStarted(int userId) {
- synchronized (mUserWakeupLock) {
- mStartingUsers.delete(userId);
+ if (deleteWakeupFromStartingUsers(userId)) {
+ updateUserListFile();
}
- updateUserListFile();
}
/**
* Remove userId from the store when the user is removed.
*/
public void onUserRemoved(int userId) {
- synchronized (mUserWakeupLock) {
- mUserStarts.delete(userId);
- mStartingUsers.delete(userId);
+ if (deleteWakeupFromUserStarts(userId) || deleteWakeupFromStartingUsers(userId)) {
+ updateUserListFile();
}
- updateUserListFile();
+ }
+
+ /**
+ * Remove wakeup for a given userId from mUserStarts.
+ * @return true if an entry is found and the list of wakeups changes.
+ */
+ private boolean deleteWakeupFromUserStarts(int userId) {
+ int index;
+ synchronized (mUserWakeupLock) {
+ index = mUserStarts.indexOfKey(userId);
+ if (index >= 0) {
+ mUserStarts.removeAt(index);
+ }
+ }
+ return index >= 0;
+ }
+
+ /**
+ * Remove wakeup for a given userId from mStartingUsers.
+ * @return true if an entry is found and the list of wakeups changes.
+ */
+ private boolean deleteWakeupFromStartingUsers(int userId) {
+ int index;
+ synchronized (mUserWakeupLock) {
+ index = mStartingUsers.indexOfKey(userId);
+ if (index >= 0) {
+ mStartingUsers.removeAt(index);
+ }
+ }
+ return index >= 0;
}
/**
diff --git a/core/api/current.txt b/core/api/current.txt
index 7d9ce58..2f2a765 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -32743,7 +32743,7 @@
field public static final int S_V2 = 32; // 0x20
field public static final int TIRAMISU = 33; // 0x21
field public static final int UPSIDE_DOWN_CAKE = 34; // 0x22
- field public static final int VANILLA_ICE_CREAM = 10000; // 0x2710
+ field public static final int VANILLA_ICE_CREAM = 35; // 0x23
}
public final class Bundle extends android.os.BaseBundle implements java.lang.Cloneable android.os.Parcelable {
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 5a3ff83..0372b7b 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -596,6 +596,7 @@
method @Deprecated public int getDeviceOwnerType(@NonNull android.content.ComponentName);
method @Nullable public String getDevicePolicyManagementRoleHolderUpdaterPackage();
method @NonNull public java.util.Set<java.lang.String> getDisallowedSystemApps(@NonNull android.content.ComponentName, int, @NonNull String);
+ method @FlaggedApi("android.app.admin.flags.headless_device_owner_provisioning_fix_enabled") @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public int getHeadlessDeviceOwnerMode();
method public long getLastBugReportRequestTime();
method public long getLastNetworkLogRetrievalTime();
method public long getLastSecurityLogRetrievalTime();
@@ -1770,14 +1771,16 @@
}
public final class InputManager {
- method public void addUniqueIdAssociation(@NonNull String, @NonNull String);
+ method @RequiresPermission("android.permission.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY") public void addUniqueIdAssociation(@NonNull String, @NonNull String);
+ method @FlaggedApi("com.android.input.flags.device_associations") @RequiresPermission("android.permission.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY") public void addUniqueIdAssociationByDescriptor(@NonNull String, @NonNull String);
method @RequiresPermission(android.Manifest.permission.REMAP_MODIFIER_KEYS) public void clearAllModifierKeyRemappings();
method @NonNull public java.util.List<java.lang.String> getKeyboardLayoutDescriptors();
method @NonNull public String getKeyboardLayoutTypeForLayoutDescriptor(@NonNull String);
method @NonNull @RequiresPermission(android.Manifest.permission.REMAP_MODIFIER_KEYS) public java.util.Map<java.lang.Integer,java.lang.Integer> getModifierKeyRemapping();
method public int getMousePointerSpeed();
method @RequiresPermission(android.Manifest.permission.REMAP_MODIFIER_KEYS) public void remapModifierKey(int, int);
- method public void removeUniqueIdAssociation(@NonNull String);
+ method @RequiresPermission("android.permission.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY") public void removeUniqueIdAssociation(@NonNull String);
+ method @FlaggedApi("com.android.input.flags.device_associations") @RequiresPermission("android.permission.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY") public void removeUniqueIdAssociationByDescriptor(@NonNull String);
field public static final long BLOCK_UNTRUSTED_TOUCHES = 158002302L; // 0x96aec7eL
}
diff --git a/core/api/test-lint-baseline.txt b/core/api/test-lint-baseline.txt
index 685ea63..c4fe061 100644
--- a/core/api/test-lint-baseline.txt
+++ b/core/api/test-lint-baseline.txt
@@ -977,8 +977,12 @@
Method 'setHdmiCecVersion' documentation mentions permissions already declared by @RequiresPermission
RequiresPermission: android.hardware.input.InputManager#addUniqueIdAssociation(String, String):
Method 'addUniqueIdAssociation' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.hardware.input.InputManager#addUniqueIdAssociationByDescriptor(String, String):
+ Method 'addUniqueIdAssociationByDescriptor' documentation mentions permissions already declared by @RequiresPermission
RequiresPermission: android.hardware.input.InputManager#removeUniqueIdAssociation(String):
Method 'removeUniqueIdAssociation' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.hardware.input.InputManager#removeUniqueIdAssociationByDescriptor(String):
+ Method 'removeUniqueIdAssociationByDescriptor' documentation mentions permissions already declared by @RequiresPermission
RequiresPermission: android.hardware.location.GeofenceHardware#addGeofence(int, int, android.hardware.location.GeofenceHardwareRequest, android.hardware.location.GeofenceHardwareCallback):
Method 'addGeofence' documentation mentions permissions without declaring @RequiresPermission
RequiresPermission: android.hardware.location.GeofenceHardware#getMonitoringTypes():
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 714454b..b19dc8f 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -5709,6 +5709,7 @@
TemplateBindResult result) {
p.headerless(resId == getBaseLayoutResource()
|| resId == getHeadsUpBaseLayoutResource()
+ || resId == getCompactHeadsUpBaseLayoutResource()
|| resId == getMessagingLayoutResource()
|| resId == R.layout.notification_template_material_media);
RemoteViews contentView = new BuilderRemoteViews(mContext.getApplicationInfo(), resId);
@@ -6594,6 +6595,36 @@
}
/**
+ * Construct a RemoteViews for the final compact heads-up notification layout.
+ * @hide
+ */
+ public RemoteViews createCompactHeadsUpContentView() {
+ // TODO(b/336225281): re-evaluate custom view usage.
+ if (useExistingRemoteView(mN.headsUpContentView)) {
+ return fullyCustomViewRequiresDecoration(false /* fromStyle */)
+ ? minimallyDecoratedHeadsUpContentView(mN.headsUpContentView)
+ : mN.headsUpContentView;
+ } else if (mStyle != null) {
+ final RemoteViews styleView = mStyle.makeCompactHeadsUpContentView();
+ if (styleView != null) {
+ return styleView;
+ }
+ }
+
+ final StandardTemplateParams p = mParams.reset()
+ .viewType(StandardTemplateParams.VIEW_TYPE_HEADS_UP)
+ .fillTextsFrom(this);
+ // Notification text is shown as secondary header text
+ // for the minimal hun when it is provided.
+ // Time(when and chronometer) is not shown for the minimal hun.
+ p.headerTextSecondary(p.mText).text(null).hideTime(true);
+
+ return applyStandardTemplate(
+ getCompactHeadsUpBaseLayoutResource(), p,
+ null /* result */);
+ }
+
+ /**
* Construct a RemoteViews representing the heads up notification layout.
*
* @deprecated For performance and system health reasons, this API is no longer required to
@@ -7269,6 +7300,10 @@
return R.layout.notification_template_material_heads_up_base;
}
+ private int getCompactHeadsUpBaseLayoutResource() {
+ return R.layout.notification_template_material_compact_heads_up_base;
+ }
+
private int getBigBaseLayoutResource() {
return R.layout.notification_template_material_big_base;
}
@@ -7795,6 +7830,16 @@
}
/**
+ * Construct a Style-specific RemoteViews for the final compact HUN layout.
+ * return null to use the standard compact heads up view.
+ * @hide
+ */
+ @Nullable
+ public RemoteViews makeCompactHeadsUpContentView() {
+ return null;
+ }
+
+ /**
* Apply any style-specific extras to this notification before shipping it out.
* @hide
*/
@@ -9106,6 +9151,16 @@
/**
* @hide
*/
+ @Nullable
+ @Override
+ public RemoteViews makeCompactHeadsUpContentView() {
+ // TODO(b/336229954): Apply minimal HUN treatment to Messaging Notifications.
+ return makeHeadsUpContentView(false);
+ }
+
+ /**
+ * @hide
+ */
@Override
public void reduceImageSizes(Context context) {
super.reduceImageSizes(context);
@@ -10275,6 +10330,16 @@
/**
* @hide
*/
+ @Nullable
+ @Override
+ public RemoteViews makeCompactHeadsUpContentView() {
+ // TODO(b/336228700): Apply minimal HUN treatment for Call Style.
+ return makeHeadsUpContentView(false);
+ }
+
+ /**
+ * @hide
+ */
public RemoteViews makeBigContentView() {
return makeCallLayout(StandardTemplateParams.VIEW_TYPE_BIG);
}
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 9058713..69f29f3 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -58,6 +58,7 @@
import static android.app.admin.flags.Flags.FLAG_DEVICE_THEFT_API_ENABLED;
import static android.app.admin.flags.Flags.FLAG_ESIM_MANAGEMENT_ENABLED;
import static android.app.admin.flags.Flags.FLAG_DEVICE_POLICY_SIZE_TRACKING_ENABLED;
+import static android.app.admin.flags.Flags.FLAG_HEADLESS_DEVICE_OWNER_PROVISIONING_FIX_ENABLED;
import static android.app.admin.flags.Flags.FLAG_HEADLESS_DEVICE_OWNER_SINGLE_USER_ENABLED;
import static android.app.admin.flags.Flags.FLAG_SECURITY_LOG_V2_ENABLED;
import static android.app.admin.flags.Flags.onboardingBugreportV2Enabled;
@@ -17724,6 +17725,9 @@
*
* @hide
*/
+ @TestApi
+ @FlaggedApi(FLAG_HEADLESS_DEVICE_OWNER_PROVISIONING_FIX_ENABLED)
+ @RequiresPermission(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS)
@DeviceAdminInfo.HeadlessDeviceOwnerMode
public int getHeadlessDeviceOwnerMode() {
if (!Flags.headlessDeviceOwnerProvisioningFixEnabled()) {
diff --git a/core/java/android/app/notification.aconfig b/core/java/android/app/notification.aconfig
index e694ccc..e3c367f8 100644
--- a/core/java/android/app/notification.aconfig
+++ b/core/java/android/app/notification.aconfig
@@ -138,4 +138,11 @@
namespace: "systemui"
description: "Cleans up spans and unnecessary new lines from standard notification templates"
bug: "313439845"
-}
\ No newline at end of file
+}
+
+flag {
+ name: "compact_heads_up_notification"
+ namespace: "systemui"
+ description: "[Minimal HUN] Enables the compact heads up notification feature"
+ bug: "270709257"
+}
diff --git a/core/java/android/companion/CompanionDeviceManager.java b/core/java/android/companion/CompanionDeviceManager.java
index a08d659..e812d81 100644
--- a/core/java/android/companion/CompanionDeviceManager.java
+++ b/core/java/android/companion/CompanionDeviceManager.java
@@ -1884,7 +1884,7 @@
mLocalOut = new ParcelFileDescriptor.AutoCloseOutputStream(localFd);
try {
- mService.attachSystemDataTransport(mContext.getPackageName(),
+ mService.attachSystemDataTransport(mContext.getOpPackageName(),
mContext.getUserId(), mAssociationId, remoteFd);
} catch (RemoteException e) {
throw new IOException("Failed to configure transport", e);
@@ -1921,9 +1921,9 @@
mStopped = true;
try {
- mService.detachSystemDataTransport(mContext.getPackageName(),
+ mService.detachSystemDataTransport(mContext.getOpPackageName(),
mContext.getUserId(), mAssociationId);
- } catch (RemoteException e) {
+ } catch (RemoteException | IllegalArgumentException e) {
Log.w(TAG, "Failed to detach transport", e);
}
diff --git a/core/java/android/content/pm/multiuser.aconfig b/core/java/android/content/pm/multiuser.aconfig
index c57a3a6..cd1913b 100644
--- a/core/java/android/content/pm/multiuser.aconfig
+++ b/core/java/android/content/pm/multiuser.aconfig
@@ -61,6 +61,13 @@
}
flag {
+ name: "new_multiuser_settings_ux"
+ namespace: "multiuser"
+ description: "Update multiuser settings UI"
+ bug: "298008926"
+}
+
+flag {
name: "enable_biometrics_to_unlock_private_space"
is_exported: true
namespace: "profile_experiences"
diff --git a/core/java/android/hardware/input/IInputManager.aidl b/core/java/android/hardware/input/IInputManager.aidl
index 1c37aa2..243ae14 100644
--- a/core/java/android/hardware/input/IInputManager.aidl
+++ b/core/java/android/hardware/input/IInputManager.aidl
@@ -165,9 +165,16 @@
// static association for the cleared input port will be restored.
void removePortAssociation(in String inputPort);
- // Add a runtime association between the input device and display.
+ // Add a runtime association between the input device and display, using device's descriptor.
+ void addUniqueIdAssociationByDescriptor(in String inputDeviceDescriptor,
+ in String displayUniqueId);
+ // Remove the runtime association between the input device and display, using device's
+ // descriptor.
+ void removeUniqueIdAssociationByDescriptor(in String inputDeviceDescriptor);
+
+ // Add a runtime association between the input device and display, using device's port.
void addUniqueIdAssociation(in String inputPort, in String displayUniqueId);
- // Remove the runtime association between the input device and display.
+ // Remove the runtime association between the input device and display, using device's port.
void removeUniqueIdAssociation(in String inputPort);
InputSensorInfo[] getSensorList(int deviceId);
diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java
index f949158..dd4ea31 100644
--- a/core/java/android/hardware/input/InputManager.java
+++ b/core/java/android/hardware/input/InputManager.java
@@ -17,6 +17,7 @@
package android.hardware.input;
import static com.android.input.flags.Flags.FLAG_INPUT_DEVICE_VIEW_BEHAVIOR_API;
+import static com.android.input.flags.Flags.FLAG_DEVICE_ASSOCIATIONS;
import static com.android.hardware.input.Flags.keyboardLayoutPreviewFlag;
import android.Manifest;
@@ -1054,13 +1055,14 @@
/**
* Add a runtime association between the input port and the display port. This overrides any
* static associations.
- * @param inputPort The port of the input device.
- * @param displayPort The physical port of the associated display.
+ * @param inputPort the port of the input device
+ * @param displayPort the physical port of the associated display
* <p>
* Requires {@link android.Manifest.permission#ASSOCIATE_INPUT_DEVICE_TO_DISPLAY}.
* </p>
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY)
public void addPortAssociation(@NonNull String inputPort, int displayPort) {
try {
mIm.addPortAssociation(inputPort, displayPort);
@@ -1072,12 +1074,13 @@
/**
* Remove the runtime association between the input port and the display port. Any existing
* static association for the cleared input port will be restored.
- * @param inputPort The port of the input device to be cleared.
+ * @param inputPort the port of the input device to be cleared
* <p>
* Requires {@link android.Manifest.permission#ASSOCIATE_INPUT_DEVICE_TO_DISPLAY}.
* </p>
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY)
public void removePortAssociation(@NonNull String inputPort) {
try {
mIm.removePortAssociation(inputPort);
@@ -1089,14 +1092,16 @@
/**
* Add a runtime association between the input port and display, by unique id. Input ports are
* expected to be unique.
- * @param inputPort The port of the input device.
- * @param displayUniqueId The unique id of the associated display.
+ * @param inputPort the port of the input device
+ * @param displayUniqueId the unique id of the associated display
* <p>
* Requires {@link android.Manifest.permission#ASSOCIATE_INPUT_DEVICE_TO_DISPLAY}.
* </p>
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY)
@TestApi
+ // TODO(b/324075859): Rename to addUniqueIdAssociationByPort
public void addUniqueIdAssociation(@NonNull String inputPort,
@NonNull String displayUniqueId) {
mGlobal.addUniqueIdAssociation(inputPort, displayUniqueId);
@@ -1104,18 +1109,60 @@
/**
* Removes a runtime association between the input device and display.
- * @param inputPort The port of the input device.
+ * @param inputPort the port of the input device
* <p>
* Requires {@link android.Manifest.permission#ASSOCIATE_INPUT_DEVICE_TO_DISPLAY}.
* </p>
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY)
@TestApi
+ // TODO(b/324075859): Rename to removeUniqueIdAssociationByPort
public void removeUniqueIdAssociation(@NonNull String inputPort) {
mGlobal.removeUniqueIdAssociation(inputPort);
}
/**
+ * Add a runtime association between the input device name and display, by descriptor. Input
+ * device descriptors are expected to be unique per physical device, though one physical
+ * device can have multiple virtual input devices that possess the same descriptor.
+ * E.g. a keyboard with built in trackpad will be 2 different input devices with the same
+ * descriptor.
+ * @param inputDeviceDescriptor the descriptor of the input device
+ * @param displayUniqueId the unique id of the associated display
+ * <p>
+ * Requires {@link android.Manifest.permissions.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY}.
+ * </p>
+ * @hide
+ */
+ @FlaggedApi(FLAG_DEVICE_ASSOCIATIONS)
+ @RequiresPermission(android.Manifest.permission.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY)
+ @TestApi
+ public void addUniqueIdAssociationByDescriptor(@NonNull String inputDeviceDescriptor,
+ @NonNull String displayUniqueId) {
+ mGlobal.addUniqueIdAssociationByDescriptor(inputDeviceDescriptor, displayUniqueId);
+ }
+
+ /**
+ * Removes a runtime association between the input device and display.
+ }
+
+ /**
+ * Removes a runtime association between the input device and display.
+ * @param inputDeviceDescriptor the descriptor of the input device
+ * <p>
+ * Requires {@link android.Manifest.permissions.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY}.
+ * </p>
+ * @hide
+ */
+ @FlaggedApi(FLAG_DEVICE_ASSOCIATIONS)
+ @RequiresPermission(android.Manifest.permission.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY)
+ @TestApi
+ public void removeUniqueIdAssociationByDescriptor(@NonNull String inputDeviceDescriptor) {
+ mGlobal.removeUniqueIdAssociationByDescriptor(inputDeviceDescriptor);
+ }
+
+ /**
* Reports the version of the Universal Stylus Initiative (USI) protocol supported by the given
* display, if any.
*
diff --git a/core/java/android/hardware/input/InputManagerGlobal.java b/core/java/android/hardware/input/InputManagerGlobal.java
index 7b29666..a9c97b1 100644
--- a/core/java/android/hardware/input/InputManagerGlobal.java
+++ b/core/java/android/hardware/input/InputManagerGlobal.java
@@ -1489,6 +1489,29 @@
}
/**
+ * @see InputManager#addUniqueIdAssociationByDescriptor(String, String)
+ */
+ public void addUniqueIdAssociationByDescriptor(@NonNull String inputDeviceDescriptor,
+ @NonNull String displayUniqueId) {
+ try {
+ mIm.addUniqueIdAssociationByDescriptor(inputDeviceDescriptor, displayUniqueId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * @see InputManager#removeUniqueIdAssociationByDescriptor(String)
+ */
+ public void removeUniqueIdAssociationByDescriptor(@NonNull String inputDeviceDescriptor) {
+ try {
+ mIm.removeUniqueIdAssociationByDescriptor(inputDeviceDescriptor);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* @see InputManager#getInputDeviceBluetoothAddress(int)
*/
@RequiresPermission(Manifest.permission.BLUETOOTH)
diff --git a/core/java/android/hardware/location/ContextHubClient.java b/core/java/android/hardware/location/ContextHubClient.java
index 01dccd1..953086d 100644
--- a/core/java/android/hardware/location/ContextHubClient.java
+++ b/core/java/android/hardware/location/ContextHubClient.java
@@ -205,14 +205,12 @@
@FlaggedApi(Flags.FLAG_RELIABLE_MESSAGE)
public ContextHubTransaction<Void> sendReliableMessageToNanoApp(
@NonNull NanoAppMessage message) {
- if (!Flags.reliableMessageImplementation()) {
- return null;
- }
-
ContextHubTransaction<Void> transaction =
new ContextHubTransaction<>(ContextHubTransaction.TYPE_RELIABLE_MESSAGE);
- if (!mAttachedHub.supportsReliableMessages()) {
+ if (!Flags.reliableMessageImplementation() ||
+ !mAttachedHub.supportsReliableMessages() ||
+ message.isBroadcastMessage()) {
transaction.setResponse(new ContextHubTransaction.Response<Void>(
ContextHubTransaction.RESULT_FAILED_NOT_SUPPORTED, null));
return transaction;
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 2b6b358..4512180 100755
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -1229,7 +1229,7 @@
/**
* Vanilla Ice Cream.
*/
- public static final int VANILLA_ICE_CREAM = CUR_DEVELOPMENT;
+ public static final int VANILLA_ICE_CREAM = 35;
}
/** The type of build, like "user" or "eng". */
diff --git a/core/java/android/os/OWNERS b/core/java/android/os/OWNERS
index 90279c6..9f3364f 100644
--- a/core/java/android/os/OWNERS
+++ b/core/java/android/os/OWNERS
@@ -88,6 +88,8 @@
# PerformanceHintManager
per-file PerformanceHintManager.java = file:/ADPF_OWNERS
per-file WorkDuration.java = file:/ADPF_OWNERS
+per-file IHintManager.aidl = file:/ADPF_OWNERS
+per-file IHintSession.aidl = file:/ADPF_OWNERS
# IThermal interfaces
per-file IThermal* = file:/THERMAL_OWNERS
diff --git a/core/java/android/os/flags.aconfig b/core/java/android/os/flags.aconfig
index fd955e2..e82c4b0 100644
--- a/core/java/android/os/flags.aconfig
+++ b/core/java/android/os/flags.aconfig
@@ -139,6 +139,13 @@
}
flag {
+ name: "adpf_measure_during_input_event_boost"
+ namespace: "game"
+ description: "Guards use of a boost when view measures during input events"
+ bug: "256549451"
+}
+
+flag {
name: "battery_service_support_current_adb_command"
namespace: "backstage_power"
description: "Whether or not BatteryService supports adb commands for Current values."
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 16649e8..095ab70 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -12629,6 +12629,15 @@
* @hide
*/
public static final String V_TO_U_RESTORE_DENYLIST = "v_to_u_restore_denylist";
+
+ /**
+ * Integer property that determines which charging optimization mode is applied.
+ * [0-10] inclusive representing different modes, where 0 is the default indicating
+ * no optimization mode is applied.
+ *
+ * @hide
+ */
+ public static final String CHARGE_OPTIMIZATION_MODE = "charge_optimization_mode";
}
/**
diff --git a/core/java/android/view/ImeBackAnimationController.java b/core/java/android/view/ImeBackAnimationController.java
index ed049b5..e14ddd6 100644
--- a/core/java/android/view/ImeBackAnimationController.java
+++ b/core/java/android/view/ImeBackAnimationController.java
@@ -70,13 +70,13 @@
@Override
public void onBackStarted(@NonNull BackEvent backEvent) {
- if (isAdjustResize()) {
+ if (!isBackAnimationAllowed()) {
// There is no good solution for a predictive back animation if the app uses
// adjustResize, since we can't relayout the whole app for every frame. We also don't
// want to reveal any black areas behind the IME. Therefore let's not play any animation
// in that case for now.
Log.d(TAG, "onBackStarted -> not playing predictive back animation due to softinput"
- + " mode adjustResize");
+ + " mode adjustResize AND no animation callback registered");
return;
}
if (isHideAnimationInProgress()) {
@@ -128,13 +128,13 @@
@Override
public void onBackCancelled() {
- if (isAdjustResize()) return;
+ if (!isBackAnimationAllowed()) return;
startPostCommitAnim(/*hideIme*/ false);
}
@Override
public void onBackInvoked() {
- if (isAdjustResize()) {
+ if (!isBackAnimationAllowed()) {
mInsetsController.hide(ime());
return;
}
@@ -252,9 +252,12 @@
}
}
- private boolean isAdjustResize() {
+ private boolean isBackAnimationAllowed() {
+ // back animation is allowed in all cases except when softInputMode is adjust_resize AND
+ // there is no app-registered WindowInsetsAnimationCallback.
return (mViewRoot.mWindowAttributes.softInputMode & SOFT_INPUT_MASK_ADJUST)
- == SOFT_INPUT_ADJUST_RESIZE;
+ != SOFT_INPUT_ADJUST_RESIZE
+ || (mViewRoot.mView != null && mViewRoot.mView.hasWindowInsetsAnimationCallback());
}
private boolean isAdjustPan() {
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 2a1eb97..510a4a3 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -160,6 +160,7 @@
import android.util.SparseIntArray;
import android.util.StateSet;
import android.util.SuperNotCalledException;
+import android.util.TimeUtils;
import android.util.TypedValue;
import android.view.AccessibilityIterators.CharacterTextSegmentIterator;
import android.view.AccessibilityIterators.ParagraphTextSegmentIterator;
@@ -18097,6 +18098,24 @@
}
/**
+ * Called by {@link #measure(int, int)} to check if the current frame presentation got
+ * delayed by an expensive view mesures during the input event dispatching. (e.g. scrolling)
+ */
+ private boolean hasExpensiveMeasuresDuringInputEvent() {
+ final AttachInfo attachInfo = mAttachInfo;
+ if (attachInfo == null || attachInfo.mRootView == null) {
+ return false;
+ }
+ if (!attachInfo.mHandlingPointerEvent) {
+ return false;
+ }
+ final ViewFrameInfo info = attachInfo.mViewRootImpl.mViewFrameInfo;
+ final long durationFromVsyncTimeMs = (System.nanoTime()
+ - Choreographer.getInstance().getLastFrameTimeNanos()) / TimeUtils.NANOS_PER_MS;
+ return durationFromVsyncTimeMs > 3L || info.getAndIncreaseViewMeasuredCount() > 10;
+ }
+
+ /**
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
@@ -28116,6 +28135,15 @@
if (isTraversalTracingEnabled()) {
Trace.beginSection(mTracingStrings.onMeasure);
}
+ if (android.os.Flags.adpfMeasureDuringInputEventBoost()) {
+ final boolean notifyRenderer = hasExpensiveMeasuresDuringInputEvent();
+ if (notifyRenderer) {
+ Trace.traceBegin(Trace.TRACE_TAG_VIEW,
+ "CPU_LOAD_UP: " + "hasExpensiveMeasuresDuringInputEvent");
+ getViewRootImpl().notifyRendererOfExpensiveFrame();
+ Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+ }
+ }
// measure ourselves, this should set the measured dimension flag back
onMeasure(widthMeasureSpec, heightMeasureSpec);
if (isTraversalTracingEnabled()) {
@@ -33942,7 +33970,7 @@
return; // can't vote if not connected
}
float velocity = mFrameContentVelocity;
- float frameRate = mPreferredFrameRate;
+ final float frameRate = mPreferredFrameRate;
ViewParent parent = mParent;
if (velocity <= 0 && Float.isNaN(frameRate)) {
// The most common case is when nothing is set, so this special case is called
@@ -33982,13 +34010,15 @@
}
if (velocityFrameRate > 0f || frameRate > 0f) {
int compatibility;
+ float frameRateToSet;
if (frameRate >= velocityFrameRate) {
compatibility = FRAME_RATE_COMPATIBILITY_FIXED_SOURCE;
+ frameRateToSet = frameRate;
} else {
compatibility = FRAME_RATE_COMPATIBILITY_GTE;
- frameRate = velocityFrameRate;
+ frameRateToSet = velocityFrameRate;
}
- viewRootImpl.votePreferredFrameRate(frameRate, compatibility);
+ viewRootImpl.votePreferredFrameRate(frameRateToSet, compatibility);
}
}
@@ -34052,7 +34082,7 @@
*/
@FlaggedApi(FLAG_VIEW_VELOCITY_API)
public void setFrameContentVelocity(float pixelsPerSecond) {
- if (viewVelocityApi()) {
+ if (mAttachInfo != null && mAttachInfo.mViewVelocityApi) {
mFrameContentVelocity = Math.abs(pixelsPerSecond);
if (sToolkitMetricsForFrameRateDecisionFlagValue) {
@@ -34070,8 +34100,8 @@
*/
@FlaggedApi(FLAG_VIEW_VELOCITY_API)
public float getFrameContentVelocity() {
- if (viewVelocityApi()) {
- return (mFrameContentVelocity < 0f) ? 0f : mFrameContentVelocity;
+ if (mAttachInfo != null && mAttachInfo.mViewVelocityApi) {
+ return Math.max(mFrameContentVelocity, 0f);
}
return 0;
}
diff --git a/core/java/android/view/ViewFrameInfo.java b/core/java/android/view/ViewFrameInfo.java
index 36bf532..46f1472 100644
--- a/core/java/android/view/ViewFrameInfo.java
+++ b/core/java/android/view/ViewFrameInfo.java
@@ -34,6 +34,8 @@
private int mInputEventId;
+ private int mViewsMeasuredCounts;
+
/**
* Populate the missing fields using the data from ViewFrameInfo
* @param frameInfo : the structure FrameInfo object to populate
@@ -51,6 +53,7 @@
drawStart = 0;
mInputEventId = IInputConstants.INVALID_INPUT_EVENT_ID;
flags = 0;
+ mViewsMeasuredCounts = 0;
}
/**
@@ -61,6 +64,13 @@
}
/**
+ * Record the number of view being measured for the current frame.
+ */
+ public int getAndIncreaseViewMeasuredCount() {
+ return ++mViewsMeasuredCounts;
+ }
+
+ /**
* Assign the value for input event id
* @param eventId the id of the input event
*/
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 52ff142..11ad86c 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -49,7 +49,6 @@
import android.os.Bundle;
import android.os.Parcelable;
import android.os.SystemClock;
-import android.service.autofill.Flags;
import android.util.AttributeSet;
import android.util.IntArray;
import android.util.Log;
@@ -2652,10 +2651,12 @@
// Check for interception.
final boolean intercepted;
- if (actionMasked == MotionEvent.ACTION_DOWN
- || mFirstTouchTarget != null) {
+ ViewRootImpl viewRootImpl = getViewRootImpl();
+ if (actionMasked == MotionEvent.ACTION_DOWN || mFirstTouchTarget != null) {
final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
- if (!disallowIntercept) {
+ final boolean isDispatchingBack = (viewRootImpl != null
+ && viewRootImpl.getOnBackInvokedDispatcher().isDispatching());
+ if (!disallowIntercept || isDispatchingBack) { // Allow back to intercept touch
intercepted = onInterceptTouchEvent(ev);
ev.setAction(action); // restore action in case it was changed
} else {
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 84cde0d..701b2d3 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -74,6 +74,7 @@
import static android.view.ViewRootImplProto.WINDOW_ATTRIBUTES;
import static android.view.ViewRootImplProto.WIN_FRAME;
import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_OVERRIDE_LAYOUT_IN_DISPLAY_CUTOUT_MODE;
import static android.view.WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS;
import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS;
import static android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS;
@@ -1282,7 +1283,7 @@
mImeFocusController = new ImeFocusController(this);
mScrollCaptureRequestTimeout = SCROLL_CAPTURE_REQUEST_TIMEOUT_MILLIS;
- mOnBackInvokedDispatcher = new WindowOnBackInvokedDispatcher(context);
+ mOnBackInvokedDispatcher = new WindowOnBackInvokedDispatcher(context, Looper.myLooper());
if (sensitiveContentAppProtection()) {
mSensitiveContentProtectionService =
ISensitiveContentProtectionManager.Stub.asInterface(
@@ -2141,7 +2142,8 @@
private int adjustLayoutInDisplayCutoutMode(WindowManager.LayoutParams attrs) {
final int originalMode = attrs.layoutInDisplayCutoutMode;
- if ((attrs.privateFlags & PRIVATE_FLAG_EDGE_TO_EDGE_ENFORCED) != 0
+ if ((attrs.privateFlags & (PRIVATE_FLAG_EDGE_TO_EDGE_ENFORCED
+ | PRIVATE_FLAG_OVERRIDE_LAYOUT_IN_DISPLAY_CUTOUT_MODE)) != 0
&& attrs.isFullscreen()
&& attrs.getFitInsetsTypes() == 0
&& attrs.getFitInsetsSides() == 0) {
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index afe5b7e..0bc2430 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -3386,6 +3386,12 @@
public static final int PRIVATE_FLAG_IMMERSIVE_CONFIRMATION_WINDOW = 1 << 17;
/**
+ * Flag to indicate that the window is forcibly to layout under the display cutout.
+ * @hide
+ */
+ public static final int PRIVATE_FLAG_OVERRIDE_LAYOUT_IN_DISPLAY_CUTOUT_MODE = 1 << 18;
+
+ /**
* Flag to indicate that any window added by an application process that is of type
* {@link #TYPE_TOAST} or that requires
* {@link android.app.AppOpsManager#OP_SYSTEM_ALERT_WINDOW} permission should be hidden when
@@ -3505,6 +3511,7 @@
PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS,
PRIVATE_FLAG_SUSTAINED_PERFORMANCE_MODE,
PRIVATE_FLAG_IMMERSIVE_CONFIRMATION_WINDOW,
+ PRIVATE_FLAG_OVERRIDE_LAYOUT_IN_DISPLAY_CUTOUT_MODE,
SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS,
PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY,
PRIVATE_FLAG_EXCLUDE_FROM_SCREEN_MAGNIFICATION,
@@ -3587,6 +3594,10 @@
equals = PRIVATE_FLAG_IMMERSIVE_CONFIRMATION_WINDOW,
name = "IMMERSIVE_CONFIRMATION_WINDOW"),
@ViewDebug.FlagToString(
+ mask = PRIVATE_FLAG_OVERRIDE_LAYOUT_IN_DISPLAY_CUTOUT_MODE,
+ equals = PRIVATE_FLAG_OVERRIDE_LAYOUT_IN_DISPLAY_CUTOUT_MODE,
+ name = "OVERRIDE_LAYOUT_IN_DISPLAY_CUTOUT_MODE"),
+ @ViewDebug.FlagToString(
mask = SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS,
equals = SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS,
name = "HIDE_NON_SYSTEM_OVERLAY_WINDOWS"),
diff --git a/core/java/android/view/flags/refresh_rate_flags.aconfig b/core/java/android/view/flags/refresh_rate_flags.aconfig
index d0fe3e0..e3054da 100644
--- a/core/java/android/view/flags/refresh_rate_flags.aconfig
+++ b/core/java/android/view/flags/refresh_rate_flags.aconfig
@@ -61,7 +61,7 @@
name: "toolkit_frame_rate_default_normal_read_only"
namespace: "toolkit"
description: "Feature flag for setting frame rate category as NORMAL for default"
- bug: "239979904"
+ bug: "335874198"
is_fixed_read_only: true
}
@@ -69,7 +69,7 @@
name: "toolkit_frame_rate_by_size_read_only"
namespace: "toolkit"
description: "Feature flag for setting frame rate category based on size"
- bug: "239979904"
+ bug: "335874198"
is_fixed_read_only: true
}
@@ -77,7 +77,7 @@
name: "toolkit_frame_rate_velocity_mapping_read_only"
namespace: "toolkit"
description: "Feature flag for setting frame rate based on velocity"
- bug: "239979904"
+ bug: "335874198"
is_fixed_read_only: true
}
@@ -85,7 +85,7 @@
name: "toolkit_frame_rate_small_uses_percent_read_only"
namespace: "toolkit"
description: "VRR uses percent of size to consider a view to be small"
- bug: "239979904"
+ bug: "335874198"
is_fixed_read_only: true
}
@@ -93,7 +93,7 @@
name: "toolkit_frame_rate_typing_read_only"
namespace: "toolkit"
description: "Feature flag for suppressing boost on typing"
- bug: "239979904"
+ bug: "335874198"
is_fixed_read_only: true
}
@@ -101,7 +101,7 @@
name: "toolkit_frame_rate_function_enabling_read_only"
namespace: "toolkit"
description: "Feature flag to enable the functionality of the dVRR feature"
- bug: "239979904"
+ bug: "335874198"
is_fixed_read_only: true
}
@@ -109,6 +109,6 @@
name: "toolkit_frame_rate_view_enabling_read_only"
namespace: "toolkit"
description: "Feature flag to enable the functionality on views for the dVRR feature"
- bug: "239979904"
+ bug: "335874198"
is_fixed_read_only: true
}
\ No newline at end of file
diff --git a/core/java/android/widget/flags/notification_widget_flags.aconfig b/core/java/android/widget/flags/notification_widget_flags.aconfig
index 95794f3..3a39631 100644
--- a/core/java/android/widget/flags/notification_widget_flags.aconfig
+++ b/core/java/android/widget/flags/notification_widget_flags.aconfig
@@ -37,3 +37,13 @@
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ name: "big_picture_style_discard_empty_icon_bitmap_drawables"
+ namespace: "systemui"
+ description: "BigPictureStyle: Ignore Icon BitmapDrawables without Bitmaps"
+ bug: "335878768"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/TouchTracker.java b/core/java/android/window/BackTouchTracker.java
similarity index 74%
rename from libs/WindowManager/Shell/src/com/android/wm/shell/back/TouchTracker.java
rename to core/java/android/window/BackTouchTracker.java
index 8f04f12..eb23af2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/TouchTracker.java
+++ b/core/java/android/window/BackTouchTracker.java
@@ -14,22 +14,21 @@
* limitations under the License.
*/
-package com.android.wm.shell.back;
+package android.window;
import android.annotation.FloatRange;
import android.os.SystemProperties;
import android.util.MathUtils;
import android.view.MotionEvent;
import android.view.RemoteAnimationTarget;
-import android.window.BackEvent;
-import android.window.BackMotionEvent;
import java.io.PrintWriter;
/**
* Helper class to record the touch location for gesture and generate back events.
+ * @hide
*/
-class TouchTracker {
+public class BackTouchTracker {
private static final String PREDICTIVE_BACK_LINEAR_DISTANCE_PROP =
"persist.wm.debug.predictive_back_linear_distance";
private static final int LINEAR_DISTANCE = SystemProperties
@@ -53,9 +52,13 @@
private float mLatestVelocityY;
private float mStartThresholdX;
private int mSwipeEdge;
+ private boolean mShouldUpdateStartLocation = false;
private TouchTrackerState mState = TouchTrackerState.INITIAL;
- void update(float touchX, float touchY, float velocityX, float velocityY) {
+ /**
+ * Updates the tracker with a new motion event.
+ */
+ public void update(float touchX, float touchY, float velocityX, float velocityY) {
/**
* If back was previously cancelled but the user has started swiping in the forward
* direction again, restart back.
@@ -74,34 +77,52 @@
mLatestVelocityY = velocityY;
}
- void setTriggerBack(boolean triggerBack) {
+ /** Sets whether the back gesture is past the trigger threshold. */
+ public void setTriggerBack(boolean triggerBack) {
if (mTriggerBack != triggerBack && !triggerBack) {
mStartThresholdX = mLatestTouchX;
}
mTriggerBack = triggerBack;
}
- boolean getTriggerBack() {
+ /** Gets whether the back gesture is past the trigger threshold. */
+ public boolean getTriggerBack() {
return mTriggerBack;
}
- void setState(TouchTrackerState state) {
+
+ /** Returns if the start location should be updated. */
+ public boolean shouldUpdateStartLocation() {
+ return mShouldUpdateStartLocation;
+ }
+
+ /** Sets if the start location should be updated. */
+ public void setShouldUpdateStartLocation(boolean shouldUpdate) {
+ mShouldUpdateStartLocation = shouldUpdate;
+ }
+
+ /** Sets the state of the touch tracker. */
+ public void setState(TouchTrackerState state) {
mState = state;
}
- boolean isInInitialState() {
+ /** Returns if the tracker is in initial state. */
+ public boolean isInInitialState() {
return mState == TouchTrackerState.INITIAL;
}
- boolean isActive() {
+ /** Returns if a back gesture is active. */
+ public boolean isActive() {
return mState == TouchTrackerState.ACTIVE;
}
- boolean isFinished() {
+ /** Returns if a back gesture has been finished. */
+ public boolean isFinished() {
return mState == TouchTrackerState.FINISHED;
}
- void setGestureStartLocation(float touchX, float touchY, int swipeEdge) {
+ /** Sets the start location of the back gesture. */
+ public void setGestureStartLocation(float touchX, float touchY, int swipeEdge) {
mInitTouchX = touchX;
mInitTouchY = touchY;
mLatestTouchX = touchX;
@@ -110,25 +131,27 @@
mStartThresholdX = mInitTouchX;
}
- /** Update the start location used to compute the progress
- * to the latest touch location.
- */
- void updateStartLocation() {
+ /** Update the start location used to compute the progress to the latest touch location. */
+ public void updateStartLocation() {
mInitTouchX = mLatestTouchX;
mInitTouchY = mLatestTouchY;
mStartThresholdX = mInitTouchX;
+ mShouldUpdateStartLocation = false;
}
- void reset() {
+ /** Resets the tracker. */
+ public void reset() {
mInitTouchX = 0;
mInitTouchY = 0;
mStartThresholdX = 0;
mTriggerBack = false;
mState = TouchTrackerState.INITIAL;
mSwipeEdge = BackEvent.EDGE_LEFT;
+ mShouldUpdateStartLocation = false;
}
- BackMotionEvent createStartEvent(RemoteAnimationTarget target) {
+ /** Creates a start {@link BackMotionEvent}. */
+ public BackMotionEvent createStartEvent(RemoteAnimationTarget target) {
return new BackMotionEvent(
/* touchX = */ mInitTouchX,
/* touchY = */ mInitTouchY,
@@ -140,7 +163,8 @@
/* departingAnimationTarget = */ target);
}
- BackMotionEvent createProgressEvent() {
+ /** Creates a progress {@link BackMotionEvent}. */
+ public BackMotionEvent createProgressEvent() {
float progress = getProgress(mLatestTouchX);
return createProgressEvent(progress);
}
@@ -152,7 +176,7 @@
* @return progress value
*/
@FloatRange(from = 0.0, to = 1.0)
- float getProgress(float touchX) {
+ public float getProgress(float touchX) {
// If back is committed, progress is the distance between the last and first touch
// point, divided by the max drag distance. Otherwise, it's the distance between
// the last touch point and the starting threshold, divided by max drag distance.
@@ -200,11 +224,20 @@
* Maximum distance in pixels.
* Progress is considered to be completed (1f) when this limit is exceeded.
*/
- float getMaxDistance() {
+ public float getMaxDistance() {
return mMaxDistance;
}
- BackMotionEvent createProgressEvent(float progress) {
+ public float getLinearDistance() {
+ return mLinearDistance;
+ }
+
+ public float getNonLinearFactor() {
+ return mNonLinearFactor;
+ }
+
+ /** Creates a progress {@link BackMotionEvent} for the given progress. */
+ public BackMotionEvent createProgressEvent(float progress) {
return new BackMotionEvent(
/* touchX = */ mLatestTouchX,
/* touchY = */ mLatestTouchY,
@@ -216,6 +249,7 @@
/* departingAnimationTarget = */ null);
}
+ /** Sets the thresholds for computing progress. */
public void setProgressThresholds(float linearDistance, float maxDistance,
float nonLinearFactor) {
if (LINEAR_DISTANCE >= 0) {
@@ -227,13 +261,14 @@
mNonLinearFactor = nonLinearFactor;
}
- void dump(PrintWriter pw, String prefix) {
- pw.println(prefix + "TouchTracker state:");
+ /** Dumps debugging info. */
+ public void dump(PrintWriter pw, String prefix) {
+ pw.println(prefix + "BackTouchTracker state:");
pw.println(prefix + " mState=" + mState);
pw.println(prefix + " mTriggerBack=" + mTriggerBack);
}
- enum TouchTrackerState {
+ public enum TouchTrackerState {
INITIAL, ACTIVE, FINISHED
}
diff --git a/core/java/android/window/IOnBackInvokedCallback.aidl b/core/java/android/window/IOnBackInvokedCallback.aidl
index 159c0e8..e07d4a9 100644
--- a/core/java/android/window/IOnBackInvokedCallback.aidl
+++ b/core/java/android/window/IOnBackInvokedCallback.aidl
@@ -56,4 +56,9 @@
* Wraps {@link OnBackInvokedCallback#onBackInvoked()}.
*/
void onBackInvoked();
+
+ /**
+ * Sets whether the back gesture is past the trigger threshold.
+ */
+ void setTriggerBack(in boolean triggerBack);
}
diff --git a/core/java/android/window/ImeOnBackInvokedDispatcher.java b/core/java/android/window/ImeOnBackInvokedDispatcher.java
index da1993d..ee6ba24 100644
--- a/core/java/android/window/ImeOnBackInvokedDispatcher.java
+++ b/core/java/android/window/ImeOnBackInvokedDispatcher.java
@@ -48,10 +48,17 @@
static final String RESULT_KEY_PRIORITY = "priority";
static final int RESULT_CODE_REGISTER = 0;
static final int RESULT_CODE_UNREGISTER = 1;
+ static final int RESULT_CODE_START_DISPATCHING = 2;
+ static final int RESULT_CODE_STOP_DISPATCHING = 3;
@NonNull
private final ResultReceiver mResultReceiver;
@NonNull
private final BackProgressAnimator mProgressAnimator = new BackProgressAnimator();
+ @NonNull
+ private final BackTouchTracker mTouchTracker = new BackTouchTracker();
+ // The handler to run callbacks on. This should be on the same thread
+ // the ViewRootImpl holding IME's WindowOnBackInvokedDispatcher is created on.
+ private Handler mHandler;
public ImeOnBackInvokedDispatcher(Handler handler) {
mResultReceiver = new ResultReceiver(handler) {
@@ -78,6 +85,10 @@
mResultReceiver = in.readTypedObject(ResultReceiver.CREATOR);
}
+ void setHandler(@NonNull Handler handler) {
+ mHandler = handler;
+ }
+
@Override
public void registerOnBackInvokedCallback(
@OnBackInvokedDispatcher.Priority int priority,
@@ -89,8 +100,13 @@
// the app process, which may treat the IME callback as weakly referenced. This will not
// cause a memory leak because the app side already clears the reference correctly.
final IOnBackInvokedCallback iCallback =
- new WindowOnBackInvokedDispatcher.OnBackInvokedCallbackWrapper(
- callback, mProgressAnimator, false /* useWeakRef */);
+ new ImeOnBackInvokedCallbackWrapper(
+ callback,
+ mTouchTracker,
+ mProgressAnimator,
+ this,
+ mHandler != null ? mHandler : Handler.getMain(),
+ false /* useWeakRef */);
bundle.putBinder(RESULT_KEY_CALLBACK, iCallback.asBinder());
bundle.putInt(RESULT_KEY_PRIORITY, priority);
bundle.putInt(RESULT_KEY_ID, callback.hashCode());
@@ -115,6 +131,12 @@
dest.writeTypedObject(mResultReceiver, flags);
}
+ /** Sets the progress thresholds for touch tracking */
+ public void setProgressThresholds(float linearDistance, float maxDistance,
+ float nonLinearFactor) {
+ mTouchTracker.setProgressThresholds(linearDistance, maxDistance, nonLinearFactor);
+ }
+
@NonNull
public static final Parcelable.Creator<ImeOnBackInvokedDispatcher> CREATOR =
new Parcelable.Creator<ImeOnBackInvokedDispatcher>() {
@@ -131,15 +153,20 @@
private void receive(
int resultCode, Bundle resultData,
@NonNull WindowOnBackInvokedDispatcher receivingDispatcher) {
- final int callbackId = resultData.getInt(RESULT_KEY_ID);
if (resultCode == RESULT_CODE_REGISTER) {
+ final int callbackId = resultData.getInt(RESULT_KEY_ID);
int priority = resultData.getInt(RESULT_KEY_PRIORITY);
final IOnBackInvokedCallback callback = IOnBackInvokedCallback.Stub.asInterface(
resultData.getBinder(RESULT_KEY_CALLBACK));
registerReceivedCallback(
callback, priority, callbackId, receivingDispatcher);
} else if (resultCode == RESULT_CODE_UNREGISTER) {
+ final int callbackId = resultData.getInt(RESULT_KEY_ID);
unregisterReceivedCallback(callbackId, receivingDispatcher);
+ } else if (resultCode == RESULT_CODE_START_DISPATCHING) {
+ receiveStartDispatching(receivingDispatcher);
+ } else if (resultCode == RESULT_CODE_STOP_DISPATCHING) {
+ receiveStopDispatching(receivingDispatcher);
}
}
@@ -181,6 +208,63 @@
mImeCallbacks.remove(callback);
}
+ static class ImeOnBackInvokedCallbackWrapper extends
+ WindowOnBackInvokedDispatcher.OnBackInvokedCallbackWrapper {
+ @NonNull
+ private final ImeOnBackInvokedDispatcher mDispatcher;
+
+ ImeOnBackInvokedCallbackWrapper(
+ @NonNull OnBackInvokedCallback callback,
+ @NonNull BackTouchTracker touchTracker,
+ @NonNull BackProgressAnimator progressAnimator,
+ @NonNull ImeOnBackInvokedDispatcher dispatcher,
+ @NonNull Handler handler,
+ boolean useWeakRef) {
+ super(callback, touchTracker, progressAnimator, handler, useWeakRef);
+ mDispatcher = dispatcher;
+ }
+
+ @Override
+ public void onBackStarted(BackMotionEvent backEvent) {
+ super.onBackStarted(backEvent);
+ mDispatcher.sendStartDispatching();
+ }
+
+ @Override
+ public void onBackCancelled() {
+ super.onBackCancelled();
+ mDispatcher.sendStopDispatching();
+ }
+
+ @Override
+ public void onBackInvoked() throws RemoteException {
+ super.onBackInvoked();
+ mDispatcher.sendStopDispatching();
+ }
+ }
+
+ /** Notifies the app process that we've stopped dispatching to an IME callback */
+ private void sendStopDispatching() {
+ mResultReceiver.send(RESULT_CODE_STOP_DISPATCHING, null /* unused bundle */);
+ }
+
+ /** Notifies the app process that we've started dispatching to an IME callback */
+ private void sendStartDispatching() {
+ mResultReceiver.send(RESULT_CODE_START_DISPATCHING, null /* unused bundle */);
+ }
+
+ /** Receives IME's message that dispatching has started. */
+ private void receiveStopDispatching(
+ @NonNull WindowOnBackInvokedDispatcher receivingDispatcher) {
+ receivingDispatcher.onStopImeDispatching();
+ }
+
+ /** Receives IME's message that dispatching has stopped. */
+ private void receiveStartDispatching(
+ @NonNull WindowOnBackInvokedDispatcher receivingDispatcher) {
+ receivingDispatcher.onStartImeDispatching();
+ }
+
/** Clears all registered callbacks on the instance. */
public void clear() {
// Unregister previously registered callbacks if there's any.
@@ -193,6 +277,7 @@
// We should also stop running animations since all callbacks have been removed.
// note: mSpring.skipToEnd(), in ProgressAnimator.reset(), requires the main handler.
Handler.getMain().post(mProgressAnimator::reset);
+ sendStopDispatching();
}
static class ImeOnBackInvokedCallback implements OnBackInvokedCallback {
diff --git a/core/java/android/window/WindowOnBackInvokedDispatcher.java b/core/java/android/window/WindowOnBackInvokedDispatcher.java
index 47a4052..7f6678e 100644
--- a/core/java/android/window/WindowOnBackInvokedDispatcher.java
+++ b/core/java/android/window/WindowOnBackInvokedDispatcher.java
@@ -23,19 +23,24 @@
import android.content.ContextWrapper;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
+import android.content.res.Configuration;
+import android.content.res.Resources;
import android.content.res.TypedArray;
import android.os.Handler;
+import android.os.Looper;
import android.os.RemoteException;
import android.os.SystemProperties;
import android.text.TextUtils;
import android.util.Log;
+import android.util.TypedValue;
import android.view.IWindow;
import android.view.IWindowSession;
import android.view.ImeBackAnimationController;
+import android.view.MotionEvent;
import androidx.annotation.VisibleForTesting;
-
+import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import java.io.PrintWriter;
@@ -63,6 +68,14 @@
public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
private IWindowSession mWindowSession;
private IWindow mWindow;
+ @VisibleForTesting
+ public final BackTouchTracker mTouchTracker = new BackTouchTracker();
+ @VisibleForTesting
+ public final BackProgressAnimator mProgressAnimator = new BackProgressAnimator();
+ // The handler to run callbacks on.
+ // This should be on the same thread the ViewRootImpl holding this instance is created on.
+ @NonNull
+ private final Handler mHandler;
private static final String TAG = "WindowOnBackDispatcher";
private static final boolean ENABLE_PREDICTIVE_BACK = SystemProperties
.getInt("persist.wm.debug.predictive_back", 1) != 0;
@@ -86,11 +99,35 @@
@GuardedBy("mLock")
public final TreeMap<Integer, ArrayList<OnBackInvokedCallback>>
mOnBackInvokedCallbacks = new TreeMap<>();
+
private Checker mChecker;
private final Object mLock = new Object();
+ // The threshold for back swipe full progress.
+ private float mBackSwipeLinearThreshold;
+ private float mNonLinearProgressFactor;
+ private boolean mImeDispatchingActive;
- public WindowOnBackInvokedDispatcher(@NonNull Context context) {
+ public WindowOnBackInvokedDispatcher(@NonNull Context context, Looper looper) {
mChecker = new Checker(context);
+ mHandler = new Handler(looper);
+ }
+
+ /** Updates the dispatcher state on a new {@link MotionEvent}. */
+ public void onMotionEvent(MotionEvent ev) {
+ if (!isDispatching() || ev == null || ev.getAction() != MotionEvent.ACTION_MOVE) {
+ return;
+ }
+ mTouchTracker.update(ev.getX(), ev.getY(), Float.NaN, Float.NaN);
+ if (mTouchTracker.shouldUpdateStartLocation()) {
+ // Reset the start location on the first event after starting back, so that
+ // the beginning of the animation feels smooth.
+ mTouchTracker.updateStartLocation();
+ }
+ if (!mProgressAnimator.isBackAnimationInProgress()) {
+ return;
+ }
+ final BackMotionEvent backEvent = mTouchTracker.createProgressEvent();
+ mProgressAnimator.onBackProgressed(backEvent);
}
/**
@@ -207,19 +244,7 @@
*/
public boolean isDispatching() {
synchronized (mLock) {
- return mIsDispatching;
- }
- }
-
- private void onStartDispatching() {
- synchronized (mLock) {
- mIsDispatching = true;
- }
- }
-
- private void onStopDispatching() {
- synchronized (mLock) {
- mIsDispatching = false;
+ return mTouchTracker.isActive() || mImeDispatchingActive;
}
}
@@ -263,7 +288,7 @@
// We should also stop running animations since all callbacks have been removed.
// note: mSpring.skipToEnd(), in ProgressAnimator.reset(), requires the main handler.
- Handler.getMain().post(mProgressAnimator::reset);
+ mHandler.post(mProgressAnimator::reset);
mAllCallbacks.clear();
mOnBackInvokedCallbacks.clear();
}
@@ -284,8 +309,9 @@
callback).getIOnBackInvokedCallback()
: new OnBackInvokedCallbackWrapper(
callback,
+ mTouchTracker,
mProgressAnimator,
- this);
+ mHandler);
callbackInfo = new OnBackInvokedCallbackInfo(
iCallback,
priority,
@@ -312,10 +338,6 @@
return null;
}
- @NonNull
- private final BackProgressAnimator mProgressAnimator = new BackProgressAnimator();
- private boolean mIsDispatching = false;
-
/**
* The {@link Context} in ViewRootImp and Activity could be different, this will make sure it
* could update the checker condition base on the real context when binding the proxy
@@ -323,6 +345,26 @@
*/
public void updateContext(@NonNull Context context) {
mChecker = new Checker(context);
+ // Set swipe threshold values.
+ Resources res = context.getResources();
+ mBackSwipeLinearThreshold =
+ res.getDimension(R.dimen.navigation_edge_action_progress_threshold);
+ TypedValue typedValue = new TypedValue();
+ res.getValue(R.dimen.back_progress_non_linear_factor, typedValue, true);
+ mNonLinearProgressFactor = typedValue.getFloat();
+ onConfigurationChanged(context.getResources().getConfiguration());
+ }
+
+ /** Updates the threshold values for computing progress. */
+ public void onConfigurationChanged(Configuration configuration) {
+ float maxDistance = configuration.windowConfiguration.getMaxBounds().width();
+ float linearDistance = Math.min(maxDistance, mBackSwipeLinearThreshold);
+ mTouchTracker.setProgressThresholds(
+ linearDistance, maxDistance, mNonLinearProgressFactor);
+ if (mImeDispatcher != null) {
+ mImeDispatcher.setProgressThresholds(
+ linearDistance, maxDistance, mNonLinearProgressFactor);
+ }
}
/**
@@ -354,6 +396,24 @@
}
}
+ /**
+ * Called when we start dispatching to a callback registered from IME.
+ */
+ public void onStartImeDispatching() {
+ synchronized (mLock) {
+ mImeDispatchingActive = true;
+ }
+ }
+
+ /**
+ * Called when we stop dispatching to a callback registered from IME.
+ */
+ public void onStopImeDispatching() {
+ synchronized (mLock) {
+ mImeDispatchingActive = false;
+ }
+ }
+
static class OnBackInvokedCallbackWrapper extends IOnBackInvokedCallback.Stub {
static class CallbackRef {
final WeakReference<OnBackInvokedCallback> mWeakRef;
@@ -376,83 +436,81 @@
}
}
final CallbackRef mCallbackRef;
- /**
- * The dispatcher this callback is registered with.
- * This can be null for callbacks on {@link ImeOnBackInvokedDispatcher} because they are
- * forwarded and registered on the app's {@link WindowOnBackInvokedDispatcher}. */
- @Nullable
- private final WindowOnBackInvokedDispatcher mDispatcher;
@NonNull
private final BackProgressAnimator mProgressAnimator;
+ @NonNull
+ private final BackTouchTracker mTouchTracker;
+ @NonNull
+ private final Handler mHandler;
OnBackInvokedCallbackWrapper(
@NonNull OnBackInvokedCallback callback,
+ @NonNull BackTouchTracker touchTracker,
@NonNull BackProgressAnimator progressAnimator,
- WindowOnBackInvokedDispatcher dispatcher) {
+ @NonNull Handler handler) {
mCallbackRef = new CallbackRef(callback, true /* useWeakRef */);
+ mTouchTracker = touchTracker;
mProgressAnimator = progressAnimator;
- mDispatcher = dispatcher;
+ mHandler = handler;
}
OnBackInvokedCallbackWrapper(
@NonNull OnBackInvokedCallback callback,
+ @NonNull BackTouchTracker touchTracker,
@NonNull BackProgressAnimator progressAnimator,
+ @NonNull Handler handler,
boolean useWeakRef) {
mCallbackRef = new CallbackRef(callback, useWeakRef);
+ mTouchTracker = touchTracker;
mProgressAnimator = progressAnimator;
- mDispatcher = null;
+ mHandler = handler;
}
@Override
public void onBackStarted(BackMotionEvent backEvent) {
- Handler.getMain().post(() -> {
- if (mDispatcher != null) {
- mDispatcher.onStartDispatching();
- }
+ mHandler.post(() -> {
+ mTouchTracker.setState(BackTouchTracker.TouchTrackerState.ACTIVE);
+ mTouchTracker.setShouldUpdateStartLocation(true);
+ mTouchTracker.setGestureStartLocation(
+ backEvent.getTouchX(), backEvent.getTouchY(), backEvent.getSwipeEdge());
+
final OnBackAnimationCallback callback = getBackAnimationCallback();
if (callback != null) {
- mProgressAnimator.reset();
callback.onBackStarted(new BackEvent(
- backEvent.getTouchX(), backEvent.getTouchY(),
- backEvent.getProgress(), backEvent.getSwipeEdge()));
+ backEvent.getTouchX(),
+ backEvent.getTouchY(),
+ backEvent.getProgress(),
+ backEvent.getSwipeEdge()));
mProgressAnimator.onBackStarted(backEvent, callback::onBackProgressed);
}
});
}
@Override
- public void onBackProgressed(BackMotionEvent backEvent) {
- Handler.getMain().post(() -> {
- final OnBackAnimationCallback callback = getBackAnimationCallback();
- if (callback != null) {
- mProgressAnimator.onBackProgressed(backEvent);
- }
- });
- }
+ public void onBackProgressed(BackMotionEvent backEvent) { }
@Override
public void onBackCancelled() {
- Handler.getMain().post(() -> {
- if (mDispatcher != null) {
- mDispatcher.onStopDispatching();
+ mHandler.post(() -> {
+ final OnBackAnimationCallback callback = getBackAnimationCallback();
+ if (callback == null) {
+ mTouchTracker.reset();
+ return;
}
mProgressAnimator.onBackCancelled(() -> {
- final OnBackAnimationCallback callback = getBackAnimationCallback();
- if (callback != null) {
- callback.onBackCancelled();
- }
+ mTouchTracker.reset();
+ callback.onBackCancelled();
});
});
}
@Override
public void onBackInvoked() throws RemoteException {
- Handler.getMain().post(() -> {
- if (mDispatcher != null) {
- mDispatcher.onStopDispatching();
- }
+ mHandler.post(() -> {
+ mTouchTracker.reset();
boolean isInProgress = mProgressAnimator.isBackAnimationInProgress();
mProgressAnimator.reset();
+ // TODO(b/333957271): Re-introduce auto fling progress generation.
final OnBackInvokedCallback callback = mCallbackRef.get();
if (callback == null) {
Log.d(TAG, "Trying to call onBackInvoked() on a null callback reference.");
@@ -466,6 +524,11 @@
});
}
+ @Override
+ public void setTriggerBack(boolean triggerBack) throws RemoteException {
+ mTouchTracker.setTriggerBack(triggerBack);
+ }
+
@Nullable
private OnBackAnimationCallback getBackAnimationCallback() {
OnBackInvokedCallback callback = mCallbackRef.get();
@@ -498,6 +561,11 @@
public void setImeOnBackInvokedDispatcher(
@NonNull ImeOnBackInvokedDispatcher imeDispatcher) {
mImeDispatcher = imeDispatcher;
+ mImeDispatcher.setHandler(mHandler);
+ mImeDispatcher.setProgressThresholds(
+ mTouchTracker.getLinearDistance(),
+ mTouchTracker.getMaxDistance(),
+ mTouchTracker.getNonLinearFactor());
}
/** Returns true if a non-null {@link ImeOnBackInvokedDispatcher} has been set. **/
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index ab37252..f4315e3 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -521,6 +521,13 @@
}
ViewRootImpl viewRootImpl = getViewRootImpl();
+ if (viewRootImpl != null) {
+ viewRootImpl.getOnBackInvokedDispatcher().onMotionEvent(event);
+ // Intercept touch if back dispatching is active.
+ if (viewRootImpl.getOnBackInvokedDispatcher().isDispatching()) {
+ return true;
+ }
+ }
if (viewRootImpl != null && mWearGestureInterceptionDetector != null) {
boolean wasIntercepting = mWearGestureInterceptionDetector.isIntercepting();
boolean intercepting = mWearGestureInterceptionDetector.onInterceptTouchEvent(event);
@@ -2125,6 +2132,11 @@
super.onConfigurationChanged(newConfig);
initializeElevation();
+
+ ViewRootImpl viewRootImpl = getViewRootImpl();
+ if (viewRootImpl != null) {
+ viewRootImpl.getOnBackInvokedDispatcher().onConfigurationChanged(newConfig);
+ }
}
@Override
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index 52487fb..a091e19 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -37,6 +37,7 @@
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_EDGE_TO_EDGE_ENFORCED;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_OVERRIDE_LAYOUT_IN_DISPLAY_CUTOUT_MODE;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -46,7 +47,9 @@
import android.app.SearchManager;
import android.app.compat.CompatChanges;
import android.compat.annotation.ChangeId;
+import android.compat.annotation.Disabled;
import android.compat.annotation.EnabledSince;
+import android.compat.annotation.Overridable;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.Intent;
@@ -180,6 +183,15 @@
@EnabledSince(targetSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM)
private static final long ENFORCE_EDGE_TO_EDGE = 309578419;
+ /**
+ * Override the layout in display cutout mode behavior. This will only apply if the edge to edge
+ * is not enforced.
+ */
+ @ChangeId
+ @Disabled
+ @Overridable
+ private static final long OVERRIDE_LAYOUT_IN_DISPLAY_CUTOUT_MODE = 332679525L;
+
private static final int CUSTOM_TITLE_COMPATIBLE_FEATURES = DEFAULT_FEATURES |
(1 << FEATURE_CUSTOM_TITLE) |
(1 << FEATURE_CONTENT_TRANSITIONS) |
@@ -2475,6 +2487,11 @@
getAttributes().privateFlags |= PRIVATE_FLAG_EDGE_TO_EDGE_ENFORCED;
mDecorFitsSystemWindows = false;
}
+ if (CompatChanges.isChangeEnabled(OVERRIDE_LAYOUT_IN_DISPLAY_CUTOUT_MODE)
+ && !a.getBoolean(R.styleable.Window_windowOptOutEdgeToEdgeEnforcement,
+ false /* defValue */)) {
+ getAttributes().privateFlags |= PRIVATE_FLAG_OVERRIDE_LAYOUT_IN_DISPLAY_CUTOUT_MODE;
+ }
mIsFloating = a.getBoolean(R.styleable.Window_windowIsFloating, false);
int flagsToUpdate = (FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR)
diff --git a/core/java/com/android/internal/widget/BigPictureNotificationImageView.java b/core/java/com/android/internal/widget/BigPictureNotificationImageView.java
index 7e7aba2..1fff0c0 100644
--- a/core/java/com/android/internal/widget/BigPictureNotificationImageView.java
+++ b/core/java/com/android/internal/widget/BigPictureNotificationImageView.java
@@ -22,6 +22,7 @@
import android.annotation.StyleRes;
import android.app.ActivityManager;
import android.content.Context;
+import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
import android.net.Uri;
@@ -29,6 +30,7 @@
import android.util.Log;
import android.widget.ImageView;
import android.widget.RemoteViews;
+import android.widget.flags.Flags;
import com.android.internal.R;
@@ -119,6 +121,22 @@
return () -> setImageDrawable(drawable);
}
+ @Override
+ public void setImageDrawable(@Nullable Drawable drawable) {
+ if (drawable instanceof BitmapDrawable bitmapDrawable) {
+ if (bitmapDrawable.getBitmap() == null) {
+ if (Flags.bigPictureStyleDiscardEmptyIconBitmapDrawables()) {
+ Log.e(TAG, "discarding BitmapDrawable with null Bitmap (invalid image file?)");
+ drawable = null;
+ } else {
+ Log.e(TAG, "setting BitmapDrawable with null Bitmap (invalid image file?)");
+ }
+ }
+ }
+
+ super.setImageDrawable(drawable);
+ }
+
private Drawable loadImage(Uri uri) {
if (uri == null) return null;
return LocalImageResolver.resolveImage(uri, mContext, mMaximumDrawableWidth,
diff --git a/core/proto/android/providers/settings/secure.proto b/core/proto/android/providers/settings/secure.proto
index f5bbbb4..9abb5c8 100644
--- a/core/proto/android/providers/settings/secure.proto
+++ b/core/proto/android/providers/settings/secure.proto
@@ -731,7 +731,9 @@
}
optional Zen zen = 71;
+ optional SettingProto charge_optimization_mode = 101 [ (android.privacy).dest = DEST_AUTOMATIC ];
+
// Please insert fields in alphabetical order and group them into messages
// if possible (to avoid reaching the method limit).
- // Next tag = 101;
+ // Next tag = 102;
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 567844c..389e087 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -298,6 +298,9 @@
<protected-broadcast android:name="android.hardware.display.action.WIFI_DISPLAY_STATUS_CHANGED" />
+ <protected-broadcast android:name="android.hardware.hdmi.action.OSD_MESSAGE" />
+ <protected-broadcast android:name="android.hardware.hdmi.action.ON_ACTIVE_SOURCE_RECOVERED_DISMISS_UI" />
+
<protected-broadcast android:name="android.hardware.usb.action.USB_STATE" />
<protected-broadcast android:name="android.hardware.usb.action.USB_PORT_CHANGED" />
<protected-broadcast android:name="android.hardware.usb.action.USB_PORT_COMPLIANCE_CHANGED" />
diff --git a/core/res/res/layout/notification_template_material_compact_heads_up_base.xml b/core/res/res/layout/notification_template_material_compact_heads_up_base.xml
new file mode 100644
index 0000000..57da898
--- /dev/null
+++ b/core/res/res/layout/notification_template_material_compact_heads_up_base.xml
@@ -0,0 +1,87 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2024 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+<FrameLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/status_bar_latest_event_content"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/notification_header_height"
+ android:clipChildren="false"
+ android:tag="compactHUN"
+ android:gravity="center_vertical"
+ android:theme="@style/Theme.DeviceDefault.Notification"
+ android:importantForAccessibility="no">
+ <com.android.internal.widget.CachingIconView
+ android:id="@+id/icon"
+ android:layout_width="@dimen/notification_icon_circle_size"
+ android:layout_height="@dimen/notification_icon_circle_size"
+ android:layout_gravity="center_vertical|start"
+ android:layout_marginStart="@dimen/notification_icon_circle_start"
+ android:background="@drawable/notification_icon_circle"
+ android:padding="@dimen/notification_icon_circle_padding"
+ android:maxDrawableWidth="@dimen/notification_icon_circle_size"
+ android:maxDrawableHeight="@dimen/notification_icon_circle_size"
+ />
+ <FrameLayout
+ android:id="@+id/alternate_expand_target"
+ android:layout_width="@dimen/notification_content_margin_start"
+ android:layout_height="match_parent"
+ android:layout_gravity="start"
+ android:importantForAccessibility="no"
+ android:focusable="false"
+ />
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_marginStart="@dimen/notification_content_margin_start"
+ android:orientation="horizontal"
+ >
+ <NotificationTopLineView
+ android:id="@+id/notification_top_line"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_centerVertical="true"
+ android:layout_weight="1"
+ android:clipChildren="false"
+ android:gravity="center_vertical"
+ android:theme="@style/Theme.DeviceDefault.Notification"
+ >
+ <TextView
+ android:id="@+id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="@dimen/notification_header_separating_margin"
+ android:ellipsize="end"
+ android:fadingEdge="horizontal"
+ android:singleLine="true"
+ android:textAlignment="viewStart"
+ android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Title"
+ />
+ <include layout="@layout/notification_top_line_views" />
+ </NotificationTopLineView>
+ <FrameLayout
+ android:id="@+id/expand_button_touch_container"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:minWidth="@dimen/notification_content_margin_end"
+ >
+ <include layout="@layout/notification_expand_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical|end"
+ />
+ </FrameLayout>
+ </LinearLayout>
+</FrameLayout>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 1a61870..b5256f8 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2042,10 +2042,17 @@
provider services. -->
<string name="config_secondaryLocationTimeZoneProviderPackageName" translatable="false"></string>
+ <!-- Whether the telephony time zone detection feature is enabled. Setting this to false means
+ the feature cannot be used. Setting this to true means the feature will be enabled on the
+ device if FEATURE_TELEPHONY
+ (@see https: //developer.android.com/reference/android/content/pm/PackageManager#FEATURE_TELEPHONY)
+ is also supported. -->
+ <bool name="config_enableTelephonyTimeZoneDetection" translatable="false">true</bool>
+
<!-- Whether the time zone detection logic supports fall back from geolocation suggestions to
telephony suggestions temporarily in certain circumstances. Reduces time zone detection
latency during some scenarios like air travel. Only useful when both geolocation and
- telephony time zone detection are supported on a device.
+ telephony time zone detection are supported and enabled on a device.
See com.android.server.timezonedetector.TimeZoneDetectorStrategy for more information. -->
<bool name="config_supportTelephonyTimeZoneFallback" translatable="false">true</bool>
@@ -4824,7 +4831,7 @@
See android.credentials.CredentialManager
-->
- <string name="config_defaultCredentialManagerAutofillService" translatable="false"></string>
+ <string name="config_defaultCredentialManagerAutofillService" translatable="false">com.android.credentialmanager/com.android.credentialmanager.autofill.CredentialAutofillService</string>
<!-- The component name(s), flattened to a string, for the system's credential manager
provider services. These services allow retrieving and storing credentials.
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 4aa741d..52ce993 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -1043,4 +1043,10 @@
<dimen name="handwriting_bounds_offset_top">40dp</dimen>
<dimen name="handwriting_bounds_offset_right">10dp</dimen>
<dimen name="handwriting_bounds_offset_bottom">40dp</dimen>
+
+ <!-- The threshold for full back swipe progress. -->
+ <dimen name="navigation_edge_action_progress_threshold">412dp</dimen>
+ <!-- The non-linear progress interval when the screen is wider than the
+ navigation_edge_action_progress_threshold. -->
+ <item name="back_progress_non_linear_factor" format="float" type="dimen">0.2</item>
</resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index e96240d..2f9f4df 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -399,28 +399,37 @@
<string name="cfTemplateRegisteredTime"><xliff:g id="bearer_service_code">{0}</xliff:g>: Not forwarded</string>
<!-- Title of the cellular network security safety center source's status. -->
- <string name="scCellularNetworkSecurityTitle">Cellular network security</string>
+ <string name="scCellularNetworkSecurityTitle">Mobile network security</string>
<!-- Summary of the cellular network security safety center source's status. -->
- <string name="scCellularNetworkSecuritySummary">Review settings</string>
+ <string name="scCellularNetworkSecuritySummary">Encryption, notifications for unencrypted networks</string>
<!-- Link passed to safety center for the Learn More button on notifications -->
<!-- DO NOT TRANSLATE -->
<string name="scCellularNetworkSecurityLearnMore" translatable="false"></string>
<!-- Title of the safety center issue and notification when the phone's identifier is shared over the network. -->
- <string name="scIdentifierDisclosureIssueTitle">Device identifier accessed</string>
- <!-- Summary of the safety center issue and notification when the phone's identifier is shared over the network. -->
- <string name="scIdentifierDisclosureIssueSummary">A network on the <xliff:g id="disclosure_network">%4$s</xliff:g> connection recorded your device\'s unique identifier (IMSI) <xliff:g id="disclosure_count">%1$d</xliff:g> times in the period between <xliff:g id="disclosure_window_start_time">%2$tr</xliff:g> and <xliff:g id="disclosure_window_end_time">%3$tr</xliff:g>.</string>
+ <string name="scIdentifierDisclosureIssueTitle">Device ID accessed</string>
+ <!-- Summary of the safety center notification when the phone's identifier is shared over the network. -->
+ <string name="scIdentifierDisclosureIssueSummaryNotification">At <xliff:g id="disclosure_time">%1$s</xliff:g>, a nearby network recorded your device\'s unique ID (IMSI or IMEI) while using your <xliff:g id="disclosure_network">%2$s</xliff:g> SIM</string>
+ <!-- Summary of the safety center detail card when the phone's identifier is shared over the network. -->
+ <string name="scIdentifierDisclosureIssueSummary">At <xliff:g id="disclosure_time">%1$s</xliff:g>, a nearby network recorded your device\'s unique ID (IMSI or IMEI) while using your <xliff:g id="disclosure_network">%2$s</xliff:g> SIM.\n\nThis means that your location, activity, or identity have been logged. This is common practice but may be an issue for people concerned about privacy.</string>
+
<!-- Title of the safety center issue and notification when the phone restores an encrypted connection to the network. -->
- <string name="scNullCipherIssueEncryptedTitle">Encrypted connection to <xliff:g id="network_name">%1$s</xliff:g></string>
+ <string name="scNullCipherIssueEncryptedTitle">Connected to encrypted network <xliff:g id="network_name">%1$s</xliff:g></string>
<!-- Summary of the safety center issue and notification when the phone restores an encrypted connection to the network. -->
- <string name="scNullCipherIssueEncryptedSummary">You\'re now connected to a more secure cellular network.</string>
+ <string name="scNullCipherIssueEncryptedSummary"><xliff:g id="network_name">%1$s</xliff:g> SIM connection is more secure now</string>
<!-- Title of the safety center issue and notification when a connected network is not using encryption. -->
- <string name="scNullCipherIssueNonEncryptedTitle">Non-encrypted connection to <xliff:g id="network_name">%1$s</xliff:g></string>
- <!-- Summary of the safety center issue and notification when a connected network is not using encryption. -->
- <string name="scNullCipherIssueNonEncryptedSummary">You\'re connected to a non-encrypted cellular network. Your calls, messages, and data are vulnerable to interception.</string>
+
+ <string name="scNullCipherIssueNonEncryptedTitle">Connected to unencrypted network</string>
+ <!-- Summary of the safety center notification when a connected network is not using encryption. -->
+ <string name="scNullCipherIssueNonEncryptedSummaryNotification">Calls, messages, and data are currently more vulnerable while using your <xliff:g id="network_name">%1$s</xliff:g> SIM</string>
+ <!-- Summary of the safety center issue when a connected network is not using encryption. -->
+ <string name="scNullCipherIssueNonEncryptedSummary">Calls, messages, and data are currently more vulnerable while using your <xliff:g id="network_name">%1$s</xliff:g> SIM.\n\nWhen your connection is encrypted again, you\'ll get another notification.</string>
+
<!-- Label for the button that links to the cellular network security settings. -->
- <string name="scNullCipherIssueActionSettings">Cellular security settings</string>
- <!-- Label for the button that link to education resourcess about cellular network security settings. -->
+ <string name="scNullCipherIssueActionSettings">Mobile network security settings</string>
+ <!-- Label for the button that links to education resourcess about cellular network security settings. -->
<string name="scNullCipherIssueActionLearnMore">Learn more</string>
+ <!-- Label for the button to acknowledge the user is connected to an encrypted network again in cellular network security settings. -->
+ <string name="scNullCipherIssueActionGotIt">Got it</string>
<!-- android.net.http Error strings --> <skip />
<!-- Displayed when a feature code (non-phone number) is dialed and completes successfully. -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 4f19c27..90132c3 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -957,12 +957,15 @@
<java-symbol type="string" name="scCellularNetworkSecurityTitle" />
<java-symbol type="string" name="scCellularNetworkSecurityLearnMore" />
<java-symbol type="string" name="scIdentifierDisclosureIssueSummary" />
+ <java-symbol type="string" name="scIdentifierDisclosureIssueSummaryNotification" />
<java-symbol type="string" name="scIdentifierDisclosureIssueTitle" />
+ <java-symbol type="string" name="scNullCipherIssueActionGotIt" />
<java-symbol type="string" name="scNullCipherIssueActionLearnMore" />
<java-symbol type="string" name="scNullCipherIssueActionSettings" />
<java-symbol type="string" name="scNullCipherIssueEncryptedSummary" />
<java-symbol type="string" name="scNullCipherIssueEncryptedTitle" />
<java-symbol type="string" name="scNullCipherIssueNonEncryptedSummary" />
+ <java-symbol type="string" name="scNullCipherIssueNonEncryptedSummaryNotification" />
<java-symbol type="string" name="scNullCipherIssueNonEncryptedTitle" />
<java-symbol type="string" name="selected" />
<java-symbol type="string" name="sendText" />
@@ -2314,6 +2317,7 @@
<java-symbol type="string" name="config_primaryLocationTimeZoneProviderPackageName" />
<java-symbol type="bool" name="config_enableSecondaryLocationTimeZoneProvider" />
<java-symbol type="string" name="config_secondaryLocationTimeZoneProviderPackageName" />
+ <java-symbol type="bool" name="config_enableTelephonyTimeZoneDetection" />
<java-symbol type="bool" name="config_supportTelephonyTimeZoneFallback" />
<java-symbol type="bool" name="config_autoResetAirplaneMode" />
<java-symbol type="string" name="config_notificationAccessConfirmationActivity" />
@@ -2338,6 +2342,7 @@
<java-symbol type="layout" name="notification_material_action_tombstone" />
<java-symbol type="layout" name="notification_template_material_base" />
<java-symbol type="layout" name="notification_template_material_heads_up_base" />
+ <java-symbol type="layout" name="notification_template_material_compact_heads_up_base" />
<java-symbol type="layout" name="notification_template_material_big_base" />
<java-symbol type="layout" name="notification_template_material_big_picture" />
<java-symbol type="layout" name="notification_template_material_inbox" />
@@ -5408,4 +5413,7 @@
<java-symbol type="integer" name="config_wallpaperFrameRateCompatibility" />
<java-symbol type="integer" name="config_defaultMinEmergencyGestureTapDurationMillis" />
+ <!-- Back swipe thresholds -->
+ <java-symbol type="dimen" name="navigation_edge_action_progress_threshold" />
+ <java-symbol type="dimen" name="back_progress_non_linear_factor" />
</resources>
diff --git a/core/tests/coretests/src/android/view/ViewFrameRateTest.java b/core/tests/coretests/src/android/view/ViewFrameRateTest.java
index 4b9aaae..4cdc993 100644
--- a/core/tests/coretests/src/android/view/ViewFrameRateTest.java
+++ b/core/tests/coretests/src/android/view/ViewFrameRateTest.java
@@ -183,6 +183,7 @@
mActivityRule.runOnUiThread(() -> {
frameLayout.setFrameContentVelocity(1f);
mMovingView.offsetTopAndBottom(100);
+ frameLayout.invalidate();
runAfterDraw(() -> assertEquals(60f, mViewRoot.getLastPreferredFrameRate(), 0f));
});
waitForAfterDraw();
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/TouchTrackerTest.kt b/core/tests/coretests/src/android/window/BackTouchTrackerTest.kt
similarity index 96%
rename from libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/TouchTrackerTest.kt
rename to core/tests/coretests/src/android/window/BackTouchTrackerTest.kt
index 6dbb1e2..b7bccd4 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/TouchTrackerTest.kt
+++ b/core/tests/coretests/src/android/window/BackTouchTrackerTest.kt
@@ -13,23 +13,22 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.wm.shell.back
+package android.window
import android.util.MathUtils
-import android.window.BackEvent
import org.junit.Assert.assertEquals
import org.junit.Test
-class TouchTrackerTest {
- private fun linearTouchTracker(): TouchTracker = TouchTracker().apply {
+class BackTouchTrackerTest {
+ private fun linearTouchTracker(): BackTouchTracker = BackTouchTracker().apply {
setProgressThresholds(MAX_DISTANCE, MAX_DISTANCE, NON_LINEAR_FACTOR)
}
- private fun nonLinearTouchTracker(): TouchTracker = TouchTracker().apply {
+ private fun nonLinearTouchTracker(): BackTouchTracker = BackTouchTracker().apply {
setProgressThresholds(LINEAR_DISTANCE, MAX_DISTANCE, NON_LINEAR_FACTOR)
}
- private fun TouchTracker.assertProgress(expected: Float) {
+ private fun BackTouchTracker.assertProgress(expected: Float) {
val actualProgress = createProgressEvent().progress
assertEquals(expected, actualProgress, /* delta = */ 0f)
}
@@ -243,4 +242,4 @@
private const val INITIAL_X_LEFT_EDGE = 5f
private const val INITIAL_X_RIGHT_EDGE = MAX_DISTANCE - INITIAL_X_LEFT_EDGE
}
-}
\ No newline at end of file
+}
diff --git a/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java b/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java
index 6321e5d..36bede9 100644
--- a/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java
+++ b/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java
@@ -20,6 +20,8 @@
import static android.window.OnBackInvokedDispatcher.PRIORITY_OVERLAY;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.atLeast;
@@ -32,10 +34,12 @@
import android.content.Context;
import android.content.pm.ApplicationInfo;
+import android.os.Looper;
import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
import android.view.IWindow;
import android.view.IWindowSession;
+import android.view.MotionEvent;
import androidx.test.filters.SmallTest;
import androidx.test.platform.app.InstrumentationRegistry;
@@ -87,6 +91,8 @@
/* triggerBack = */ false,
/* swipeEdge = */ BackEvent.EDGE_LEFT,
/* departingAnimationTarget = */ null);
+ private final MotionEvent mMotionEvent =
+ MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, 100, 100, 0);
@Before
public void setUp() throws Exception {
@@ -95,7 +101,7 @@
doReturn(true).when(mApplicationInfo).isOnBackInvokedCallbackEnabled();
doReturn(mApplicationInfo).when(mContext).getApplicationInfo();
- mDispatcher = new WindowOnBackInvokedDispatcher(mContext);
+ mDispatcher = new WindowOnBackInvokedDispatcher(mContext, Looper.getMainLooper());
mDispatcher.attachToWindow(mWindowSession, mWindow, null);
}
@@ -377,4 +383,36 @@
verify(mCallback1, never()).onBackInvoked();
verify(mCallback1).onBackCancelled();
}
+
+ @Test
+ public void updatesDispatchingState() throws RemoteException {
+ mDispatcher.registerOnBackInvokedCallback(PRIORITY_DEFAULT, mCallback1);
+ OnBackInvokedCallbackInfo callbackInfo = assertSetCallbackInfo();
+
+ callbackInfo.getCallback().onBackStarted(mBackEvent);
+ waitForIdle();
+ assertTrue(mDispatcher.isDispatching());
+
+ callbackInfo.getCallback().onBackInvoked();
+ waitForIdle();
+ assertFalse(mDispatcher.isDispatching());
+ }
+
+ @Test
+ public void handlesMotionEvent() throws RemoteException {
+ mDispatcher.registerOnBackInvokedCallback(PRIORITY_DEFAULT, mCallback1);
+ OnBackInvokedCallbackInfo callbackInfo = assertSetCallbackInfo();
+
+ mDispatcher.onMotionEvent(mMotionEvent);
+ assertFalse(mDispatcher.mTouchTracker.isActive());
+
+ callbackInfo.getCallback().onBackStarted(mBackEvent);
+ waitForIdle();
+ assertTrue(mDispatcher.isDispatching());
+ assertTrue(mDispatcher.mTouchTracker.isActive());
+
+ mDispatcher.onMotionEvent(mMotionEvent);
+ waitForIdle();
+ verify(mCallback1).onBackProgressed(any());
+ }
}
diff --git a/graphics/java/android/framework_graphics.aconfig b/graphics/java/android/framework_graphics.aconfig
index 4ab09eb..0b9e72d 100644
--- a/graphics/java/android/framework_graphics.aconfig
+++ b/graphics/java/android/framework_graphics.aconfig
@@ -16,3 +16,11 @@
description: "Feature flag for YUV image compress to Ultra HDR."
bug: "308978825"
}
+
+flag {
+ name: "icon_load_drawable_return_null_when_uri_decode_fails"
+ is_exported: true
+ namespace: "core_graphics"
+ description: "Return null when decode from URI fails in Icon.loadDrawable()"
+ bug: "335878768"
+}
diff --git a/graphics/java/android/graphics/drawable/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java
index b291f93..579ac60 100644
--- a/graphics/java/android/graphics/drawable/BitmapDrawable.java
+++ b/graphics/java/android/graphics/drawable/BitmapDrawable.java
@@ -43,6 +43,7 @@
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.LayoutDirection;
+import android.util.Log;
import android.util.TypedValue;
import android.view.Gravity;
@@ -138,6 +139,9 @@
*/
@Deprecated
public BitmapDrawable(Bitmap bitmap) {
+ if (bitmap == null) {
+ Log.w(TAG, "BitmapDrawable created with null Bitmap");
+ }
init(new BitmapState(bitmap), null);
}
@@ -146,6 +150,9 @@
* the display metrics of the resources.
*/
public BitmapDrawable(Resources res, Bitmap bitmap) {
+ if (bitmap == null) {
+ Log.w(TAG, "BitmapDrawable created with null Bitmap");
+ }
init(new BitmapState(bitmap), res);
}
@@ -177,7 +184,7 @@
} finally {
init(new BitmapState(bitmap), res);
if (mBitmapState.mBitmap == null) {
- android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + filepath);
+ Log.w(TAG, "BitmapDrawable cannot decode " + filepath);
}
}
}
@@ -210,7 +217,7 @@
} finally {
init(new BitmapState(bitmap), res);
if (mBitmapState.mBitmap == null) {
- android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + is);
+ Log.w(TAG, "BitmapDrawable cannot decode " + is);
}
}
}
@@ -1073,4 +1080,6 @@
mBitmapState.mBlendMode);
computeBitmapSize();
}
+
+ private static final String TAG = "BitmapDrawable";
}
diff --git a/graphics/java/android/graphics/drawable/Icon.java b/graphics/java/android/graphics/drawable/Icon.java
index f359025..c3aaf98 100644
--- a/graphics/java/android/graphics/drawable/Icon.java
+++ b/graphics/java/android/graphics/drawable/Icon.java
@@ -19,6 +19,8 @@
import static android.content.Context.CONTEXT_INCLUDE_CODE;
import static android.content.Context.CONTEXT_RESTRICTED;
+import static com.android.graphics.flags.Flags.iconLoadDrawableReturnNullWhenUriDecodeFails;
+
import android.annotation.ColorInt;
import android.annotation.DrawableRes;
import android.annotation.IntDef;
@@ -494,15 +496,28 @@
case TYPE_URI:
InputStream is = getUriInputStream(context);
if (is != null) {
- return new BitmapDrawable(context.getResources(),
- fixMaxBitmapSize(BitmapFactory.decodeStream(is)));
+ final Bitmap bitmap = BitmapFactory.decodeStream(is);
+ if (bitmap == null) {
+ Log.w(TAG, "Unable to decode image from URI: " + getUriString());
+ if (iconLoadDrawableReturnNullWhenUriDecodeFails()) {
+ return null;
+ }
+ }
+ return new BitmapDrawable(context.getResources(), fixMaxBitmapSize(bitmap));
}
break;
case TYPE_URI_ADAPTIVE_BITMAP:
is = getUriInputStream(context);
if (is != null) {
+ final Bitmap bitmap = BitmapFactory.decodeStream(is);
+ if (bitmap == null) {
+ Log.w(TAG, "Unable to decode image from URI: " + getUriString());
+ if (iconLoadDrawableReturnNullWhenUriDecodeFails()) {
+ return null;
+ }
+ }
return new AdaptiveIconDrawable(null, new BitmapDrawable(context.getResources(),
- fixMaxBitmapSize(BitmapFactory.decodeStream(is))));
+ fixMaxBitmapSize(bitmap)));
}
break;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimation.java
index 2643211..196f89d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimation.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimation.java
@@ -49,9 +49,9 @@
@BackEvent.SwipeEdge int swipeEdge);
/**
- * Called when the input pointers are pilfered.
+ * Called when the back swipe threshold is crossed.
*/
- void onPilferPointers();
+ void onThresholdCrossed();
/**
* Sets whether the back gesture is past the trigger threshold or not.
@@ -101,4 +101,10 @@
* @param customizer the controller to control system bar color.
*/
void setStatusBarCustomizer(StatusBarCustomizer customizer);
+
+ /**
+ * Set a callback to pilfer pointers.
+ * @param pilferCallback the callback to pilfer pointers.
+ */
+ void setPilferPointerCallback(Runnable pilferCallback);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
index d3fe4f8..163a896 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
@@ -22,9 +22,6 @@
import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_BACK_PREVIEW;
import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_BACK_ANIMATION;
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ValueAnimator;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SuppressLint;
@@ -46,7 +43,6 @@
import android.provider.Settings.Global;
import android.util.DisplayMetrics;
import android.util.Log;
-import android.util.MathUtils;
import android.view.IRemoteAnimationRunner;
import android.view.InputDevice;
import android.view.KeyCharacterMap;
@@ -57,6 +53,7 @@
import android.window.BackEvent;
import android.window.BackMotionEvent;
import android.window.BackNavigationInfo;
+import android.window.BackTouchTracker;
import android.window.IBackAnimationFinishedCallback;
import android.window.IBackAnimationRunner;
import android.window.IOnBackInvokedCallback;
@@ -118,7 +115,8 @@
/** Tracks if we should start the back gesture on the next motion move event */
private boolean mShouldStartOnNextMoveEvent = false;
private boolean mOnBackStartDispatched = false;
- private boolean mPointerPilfered = false;
+ private boolean mThresholdCrossed = false;
+ private boolean mPointersPilfered = false;
private final boolean mRequirePointerPilfer;
private final FlingAnimationUtils mFlingAnimationUtils;
@@ -139,13 +137,13 @@
/**
* Tracks the current user back gesture.
*/
- private TouchTracker mCurrentTracker = new TouchTracker();
+ private BackTouchTracker mCurrentTracker = new BackTouchTracker();
/**
* Tracks the next back gesture in case a new user gesture has started while the back animation
* (and navigation) associated with {@link #mCurrentTracker} have not yet finished.
*/
- private TouchTracker mQueuedTracker = new TouchTracker();
+ private BackTouchTracker mQueuedTracker = new BackTouchTracker();
private final Runnable mAnimationTimeoutRunnable = () -> {
ProtoLog.w(WM_SHELL_BACK_PREVIEW, "Animation didn't finish in %d ms. Resetting...",
@@ -189,6 +187,7 @@
// Keep previous navigation type before remove mBackNavigationInfo.
@BackNavigationInfo.BackTargetType
private int mPreviousNavigationType;
+ private Runnable mPilferPointerCallback;
public BackAnimationController(
@NonNull ShellInit shellInit,
@@ -335,8 +334,8 @@
}
@Override
- public void onPilferPointers() {
- BackAnimationController.this.onPilferPointers();
+ public void onThresholdCrossed() {
+ BackAnimationController.this.onThresholdCrossed();
}
@Override
@@ -358,6 +357,13 @@
mCustomizer = customizer;
mAnimationBackground.setStatusBarCustomizer(customizer);
}
+
+ @Override
+ public void setPilferPointerCallback(Runnable callback) {
+ mShellExecutor.execute(() -> {
+ mPilferPointerCallback = callback;
+ });
+ }
}
private static class IBackAnimationImpl extends IBackAnimation.Stub
@@ -414,20 +420,23 @@
mShellBackAnimationRegistry.unregisterAnimation(type);
}
- private TouchTracker getActiveTracker() {
+ private BackTouchTracker getActiveTracker() {
if (mCurrentTracker.isActive()) return mCurrentTracker;
if (mQueuedTracker.isActive()) return mQueuedTracker;
return null;
}
@VisibleForTesting
- void onPilferPointers() {
- mPointerPilfered = true;
+ public void onThresholdCrossed() {
+ mThresholdCrossed = true;
// Dispatch onBackStarted, only to app callbacks.
// System callbacks will receive onBackStarted when the remote animation starts.
- if (!shouldDispatchToAnimator() && mActiveCallback != null) {
+ final boolean shouldDispatchToAnimator = shouldDispatchToAnimator();
+ if (!shouldDispatchToAnimator && mActiveCallback != null) {
mCurrentTracker.updateStartLocation();
tryDispatchOnBackStarted(mActiveCallback, mCurrentTracker.createStartEvent(null));
+ } else if (shouldDispatchToAnimator) {
+ tryPilferPointers();
}
}
@@ -443,7 +452,7 @@
int keyAction,
@BackEvent.SwipeEdge int swipeEdge) {
- TouchTracker activeTouchTracker = getActiveTracker();
+ BackTouchTracker activeTouchTracker = getActiveTracker();
if (activeTouchTracker != null) {
activeTouchTracker.update(touchX, touchY, velocityX, velocityY);
}
@@ -487,7 +496,7 @@
// onBackCancelled event, let's interrupt it and start animating a new back gesture
resetTouchTracker();
}
- TouchTracker touchTracker;
+ BackTouchTracker touchTracker;
if (mCurrentTracker.isInInitialState()) {
touchTracker = mCurrentTracker;
} else if (mQueuedTracker.isInInitialState()) {
@@ -498,7 +507,7 @@
return;
}
touchTracker.setGestureStartLocation(touchX, touchY, swipeEdge);
- touchTracker.setState(TouchTracker.TouchTrackerState.ACTIVE);
+ touchTracker.setState(BackTouchTracker.TouchTrackerState.ACTIVE);
mBackGestureStarted = true;
if (interruptCancelPostCommitAnimation) {
@@ -514,7 +523,7 @@
}
}
- private void startBackNavigation(@NonNull TouchTracker touchTracker) {
+ private void startBackNavigation(@NonNull BackTouchTracker touchTracker) {
try {
startLatencyTracking();
mBackNavigationInfo = mActivityTaskManager.startBackNavigation(
@@ -527,7 +536,7 @@
}
private void onBackNavigationInfoReceived(@Nullable BackNavigationInfo backNavigationInfo,
- @NonNull TouchTracker touchTracker) {
+ @NonNull BackTouchTracker touchTracker) {
ProtoLog.d(WM_SHELL_BACK_PREVIEW, "Received backNavigationInfo:%s", backNavigationInfo);
if (backNavigationInfo == null) {
ProtoLog.e(WM_SHELL_BACK_PREVIEW, "Received BackNavigationInfo is null.");
@@ -540,6 +549,7 @@
if (!mShellBackAnimationRegistry.startGesture(backType)) {
mActiveCallback = null;
}
+ tryPilferPointers();
} else {
mActiveCallback = mBackNavigationInfo.getOnBackInvokedCallback();
// App is handling back animation. Cancel system animation latency tracking.
@@ -588,12 +598,22 @@
&& mBackNavigationInfo.isPrepareRemoteAnimation();
}
+ private void tryPilferPointers() {
+ if (mPointersPilfered || !mThresholdCrossed) {
+ return;
+ }
+ if (mPilferPointerCallback != null) {
+ mPilferPointerCallback.run();
+ }
+ mPointersPilfered = true;
+ }
+
private void tryDispatchOnBackStarted(
IOnBackInvokedCallback callback,
BackMotionEvent backEvent) {
if (mOnBackStartDispatched
|| callback == null
- || (!mPointerPilfered && mRequirePointerPilfer)) {
+ || (!mThresholdCrossed && mRequirePointerPilfer)) {
return;
}
dispatchOnBackStarted(callback, backEvent);
@@ -613,79 +633,6 @@
}
}
-
- /**
- * Allows us to manage the fling gesture, it smoothly animates the current progress value to
- * the final position, calculated based on the current velocity.
- *
- * @param callback the callback to be invoked when the animation ends.
- */
- private void dispatchOrAnimateOnBackInvoked(IOnBackInvokedCallback callback,
- @NonNull TouchTracker touchTracker) {
- if (callback == null) {
- return;
- }
-
- boolean animationStarted = false;
-
- if (mBackNavigationInfo != null && mBackNavigationInfo.isAnimationCallback()) {
-
- final BackMotionEvent backMotionEvent = touchTracker.createProgressEvent();
- if (backMotionEvent != null) {
- // Constraints - absolute values
- float minVelocity = mFlingAnimationUtils.getMinVelocityPxPerSecond();
- float maxVelocity = mFlingAnimationUtils.getHighVelocityPxPerSecond();
- float maxX = touchTracker.getMaxDistance(); // px
- float maxFlingDistance = maxX * MAX_FLING_PROGRESS; // px
-
- // Current state
- float currentX = backMotionEvent.getTouchX();
- float velocity = MathUtils.constrain(backMotionEvent.getVelocityX(),
- -maxVelocity, maxVelocity);
-
- // Target state
- float animationFaction = velocity / maxVelocity; // value between -1 and 1
- float flingDistance = animationFaction * maxFlingDistance; // px
- float endX = MathUtils.constrain(currentX + flingDistance, 0f, maxX);
-
- if (!Float.isNaN(endX)
- && currentX != endX
- && Math.abs(velocity) >= minVelocity) {
- ValueAnimator animator = ValueAnimator.ofFloat(currentX, endX);
-
- mFlingAnimationUtils.apply(
- /* animator = */ animator,
- /* currValue = */ currentX,
- /* endValue = */ endX,
- /* velocity = */ velocity,
- /* maxDistance = */ maxFlingDistance
- );
-
- animator.addUpdateListener(animation -> {
- Float animatedValue = (Float) animation.getAnimatedValue();
- float progress = touchTracker.getProgress(animatedValue);
- final BackMotionEvent backEvent = touchTracker.createProgressEvent(
- progress);
- dispatchOnBackProgressed(mActiveCallback, backEvent);
- });
-
- animator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- dispatchOnBackInvoked(callback);
- }
- });
- animator.start();
- animationStarted = true;
- }
- }
- }
-
- if (!animationStarted) {
- dispatchOnBackInvoked(callback);
- }
- }
-
private void dispatchOnBackInvoked(IOnBackInvokedCallback callback) {
if (callback == null) {
return;
@@ -714,7 +661,7 @@
private void dispatchOnBackProgressed(IOnBackInvokedCallback callback,
BackMotionEvent backEvent) {
- if (callback == null) {
+ if (callback == null || !shouldDispatchToAnimator()) {
return;
}
try {
@@ -728,7 +675,14 @@
* Sets to true when the back gesture has passed the triggering threshold, false otherwise.
*/
public void setTriggerBack(boolean triggerBack) {
- TouchTracker activeBackGestureInfo = getActiveTracker();
+ if (mActiveCallback != null) {
+ try {
+ mActiveCallback.setTriggerBack(triggerBack);
+ } catch (RemoteException e) {
+ Log.e(TAG, "remote setTriggerBack error: ", e);
+ }
+ }
+ BackTouchTracker activeBackGestureInfo = getActiveTracker();
if (activeBackGestureInfo != null) {
activeBackGestureInfo.setTriggerBack(triggerBack);
}
@@ -742,7 +696,7 @@
mQueuedTracker.setProgressThresholds(linearDistance, maxDistance, nonLinearFactor);
}
- private void invokeOrCancelBack(@NonNull TouchTracker touchTracker) {
+ private void invokeOrCancelBack(@NonNull BackTouchTracker touchTracker) {
// Make a synchronized call to core before dispatch back event to client side.
// If the close transition happens before the core receives onAnimationFinished, there will
// play a second close animation for that transition.
@@ -758,7 +712,7 @@
if (mBackNavigationInfo != null) {
final IOnBackInvokedCallback callback = mBackNavigationInfo.getOnBackInvokedCallback();
if (touchTracker.getTriggerBack()) {
- dispatchOrAnimateOnBackInvoked(callback, touchTracker);
+ dispatchOnBackInvoked(callback);
} else {
tryDispatchOnBackCancelled(callback);
}
@@ -770,7 +724,7 @@
* Called when the gesture is released, then it could start the post commit animation.
*/
private void onGestureFinished() {
- TouchTracker activeTouchTracker = getActiveTracker();
+ BackTouchTracker activeTouchTracker = getActiveTracker();
if (!mBackGestureStarted || activeTouchTracker == null) {
// This can happen when an unfinished gesture has been reset in resetTouchTracker
ProtoLog.d(WM_SHELL_BACK_PREVIEW,
@@ -780,8 +734,11 @@
boolean triggerBack = activeTouchTracker.getTriggerBack();
ProtoLog.d(WM_SHELL_BACK_PREVIEW, "onGestureFinished() mTriggerBack == %s", triggerBack);
+ // Reset gesture states.
+ mThresholdCrossed = false;
+ mPointersPilfered = false;
mBackGestureStarted = false;
- activeTouchTracker.setState(TouchTracker.TouchTrackerState.FINISHED);
+ activeTouchTracker.setState(BackTouchTracker.TouchTrackerState.FINISHED);
if (mPostCommitAnimationInProgress) {
ProtoLog.w(WM_SHELL_BACK_PREVIEW, "Animation is still running");
@@ -839,7 +796,7 @@
if (mCurrentTracker.getTriggerBack()) {
// notify gesture finished
mBackNavigationInfo.onBackGestureFinished(true);
- dispatchOrAnimateOnBackInvoked(mActiveCallback, mCurrentTracker);
+ dispatchOnBackInvoked(mActiveCallback);
} else {
tryDispatchOnBackCancelled(mActiveCallback);
}
@@ -882,10 +839,11 @@
}
/**
- * Resets the TouchTracker and potentially starts a new back navigation in case one is queued
+ * Resets the BackTouchTracker and potentially starts a new back navigation in case one
+ * is queued.
*/
private void resetTouchTracker() {
- TouchTracker temp = mCurrentTracker;
+ BackTouchTracker temp = mCurrentTracker;
mCurrentTracker = mQueuedTracker;
temp.reset();
mQueuedTracker = temp;
@@ -928,7 +886,8 @@
mApps = null;
mShouldStartOnNextMoveEvent = false;
mOnBackStartDispatched = false;
- mPointerPilfered = false;
+ mThresholdCrossed = false;
+ mPointersPilfered = false;
mShellBackAnimationRegistry.resetDefaultCrossActivity();
cancelLatencyTracking();
if (mBackNavigationInfo != null) {
@@ -1076,7 +1035,7 @@
pw.println(prefix + " mBackGestureStarted=" + mBackGestureStarted);
pw.println(prefix + " mPostCommitAnimationInProgress=" + mPostCommitAnimationInProgress);
pw.println(prefix + " mShouldStartOnNextMoveEvent=" + mShouldStartOnNextMoveEvent);
- pw.println(prefix + " mPointerPilfered=" + mPointerPilfered);
+ pw.println(prefix + " mPointerPilfered=" + mThresholdCrossed);
pw.println(prefix + " mRequirePointerPilfer=" + mRequirePointerPilfer);
pw.println(prefix + " mCurrentTracker state:");
mCurrentTracker.dump(pw, prefix + " ");
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
index 65169e3..f99b4b2 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
@@ -354,6 +354,7 @@
// Verify that we prevent any interaction with the animator callback in case a new gesture
// starts while the current back animation has not ended, instead the gesture is queued
triggerBackGesture();
+ verify(mAnimatorCallback).setTriggerBack(eq(true));
verifyNoMoreInteractions(mAnimatorCallback);
// Finish previous back navigation.
@@ -394,6 +395,7 @@
// starts while the current back animation has not ended, instead the gesture is queued
triggerBackGesture();
releaseBackGesture();
+ verify(mAnimatorCallback).setTriggerBack(eq(true));
verifyNoMoreInteractions(mAnimatorCallback);
// Finish previous back navigation.
@@ -532,7 +534,7 @@
}
@Test
- public void callbackShouldDeliverProgress() throws RemoteException {
+ public void appCallback_receivesStartAndInvoke() throws RemoteException {
registerAnimation(BackNavigationInfo.TYPE_RETURN_TO_HOME);
final int type = BackNavigationInfo.TYPE_CALLBACK;
@@ -551,8 +553,9 @@
assertTrue("TriggerBack should have been true", result.mTriggerBack);
verify(mAppCallback, times(1)).onBackStarted(any());
- verify(mAppCallback, times(1)).onBackProgressed(any());
verify(mAppCallback, times(1)).onBackInvoked();
+ // Progress events should be generated from the app process.
+ verify(mAppCallback, never()).onBackProgressed(any());
verify(mAnimatorCallback, never()).onBackStarted(any());
verify(mAnimatorCallback, never()).onBackProgressed(any());
@@ -639,7 +642,7 @@
*/
private void doStartEvents(int startX, int moveX) {
doMotionEvent(MotionEvent.ACTION_DOWN, startX);
- mController.onPilferPointers();
+ mController.onThresholdCrossed();
doMotionEvent(MotionEvent.ACTION_MOVE, moveX);
}
diff --git a/libs/hostgraphics/ADisplay.cpp b/libs/hostgraphics/ADisplay.cpp
index 9cc1f40..58fa082 100644
--- a/libs/hostgraphics/ADisplay.cpp
+++ b/libs/hostgraphics/ADisplay.cpp
@@ -94,14 +94,14 @@
int ADisplay_acquirePhysicalDisplays(ADisplay*** outDisplays) {
// This is running on host, so there are no physical displays available.
// Create 1 fake display instead.
- DisplayImpl** const impls = reinterpret_cast<DisplayImpl**>(
- malloc(sizeof(DisplayImpl*) + sizeof(DisplayImpl)));
+ DisplayImpl** const impls =
+ reinterpret_cast<DisplayImpl**>(malloc(sizeof(DisplayImpl*) + sizeof(DisplayImpl)));
DisplayImpl* const displayData = reinterpret_cast<DisplayImpl*>(impls + 1);
- displayData[0] = DisplayImpl{ADisplayType::DISPLAY_TYPE_INTERNAL,
- ADataSpace::ADATASPACE_UNKNOWN,
- AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
- DisplayConfigImpl()};
+ displayData[0] =
+ DisplayImpl{ADisplayType::DISPLAY_TYPE_INTERNAL, ADataSpace::ADATASPACE_UNKNOWN,
+ AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
+ DisplayConfigImpl()};
impls[0] = displayData;
*outDisplays = reinterpret_cast<ADisplay**>(impls);
return 1;
diff --git a/libs/hostgraphics/Fence.cpp b/libs/hostgraphics/Fence.cpp
index 9e54816..4383bf0 100644
--- a/libs/hostgraphics/Fence.cpp
+++ b/libs/hostgraphics/Fence.cpp
@@ -20,4 +20,4 @@
const sp<Fence> Fence::NO_FENCE = sp<Fence>(new Fence);
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/libs/hostgraphics/HostBufferQueue.cpp b/libs/hostgraphics/HostBufferQueue.cpp
index b4fd5d9..7e14b88 100644
--- a/libs/hostgraphics/HostBufferQueue.cpp
+++ b/libs/hostgraphics/HostBufferQueue.cpp
@@ -15,21 +15,26 @@
*/
#include <gui/BufferQueue.h>
-
#include <system/window.h>
namespace android {
class HostBufferQueue : public IGraphicBufferProducer, public IGraphicBufferConsumer {
public:
- HostBufferQueue() : mWidth(0), mHeight(0) { }
+ HostBufferQueue() : mWidth(0), mHeight(0) {}
-// Consumer
- virtual status_t setConsumerIsProtected(bool isProtected) { return OK; }
+ // Consumer
+ virtual status_t setConsumerIsProtected(bool isProtected) {
+ return OK;
+ }
- virtual status_t detachBuffer(int slot) { return OK; }
+ virtual status_t detachBuffer(int slot) {
+ return OK;
+ }
- virtual status_t getReleasedBuffers(uint64_t* slotMask) { return OK; }
+ virtual status_t getReleasedBuffers(uint64_t* slotMask) {
+ return OK;
+ }
virtual status_t setDefaultBufferSize(uint32_t w, uint32_t h) {
mWidth = w;
@@ -38,26 +43,36 @@
return OK;
}
- virtual status_t setDefaultBufferFormat(PixelFormat defaultFormat) { return OK; }
+ virtual status_t setDefaultBufferFormat(PixelFormat defaultFormat) {
+ return OK;
+ }
- virtual status_t setDefaultBufferDataSpace(android_dataspace defaultDataSpace) { return OK; }
+ virtual status_t setDefaultBufferDataSpace(android_dataspace defaultDataSpace) {
+ return OK;
+ }
- virtual status_t discardFreeBuffers() { return OK; }
+ virtual status_t discardFreeBuffers() {
+ return OK;
+ }
virtual status_t acquireBuffer(BufferItem* buffer, nsecs_t presentWhen,
- uint64_t maxFrameNumber = 0) {
+ uint64_t maxFrameNumber = 0) {
buffer->mGraphicBuffer = mBuffer;
buffer->mSlot = 0;
return OK;
}
- virtual status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers) { return OK; }
+ virtual status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers) {
+ return OK;
+ }
- virtual status_t setConsumerUsageBits(uint64_t usage) { return OK; }
+ virtual status_t setConsumerUsageBits(uint64_t usage) {
+ return OK;
+ }
-// Producer
+ // Producer
virtual int query(int what, int* value) {
- switch(what) {
+ switch (what) {
case NATIVE_WINDOW_WIDTH:
*value = mWidth;
break;
@@ -83,8 +98,7 @@
};
void BufferQueue::createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
- sp<IGraphicBufferConsumer>* outConsumer) {
-
+ sp<IGraphicBufferConsumer>* outConsumer) {
sp<HostBufferQueue> obj(new HostBufferQueue());
*outProducer = obj;
diff --git a/libs/hostgraphics/PublicFormat.cpp b/libs/hostgraphics/PublicFormat.cpp
index af6d273..2a2eec6 100644
--- a/libs/hostgraphics/PublicFormat.cpp
+++ b/libs/hostgraphics/PublicFormat.cpp
@@ -30,4 +30,4 @@
return static_cast<PublicFormat>(format);
}
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/libs/hostgraphics/gui/BufferItem.h b/libs/hostgraphics/gui/BufferItem.h
index 01409e1..e95a923 100644
--- a/libs/hostgraphics/gui/BufferItem.h
+++ b/libs/hostgraphics/gui/BufferItem.h
@@ -17,16 +17,15 @@
#ifndef ANDROID_GUI_BUFFERITEM_H
#define ANDROID_GUI_BUFFERITEM_H
+#include <system/graphics.h>
#include <ui/Fence.h>
#include <ui/Rect.h>
-
-#include <system/graphics.h>
-
#include <utils/StrongPointer.h>
namespace android {
class Fence;
+
class GraphicBuffer;
// The only thing we need here for layoutlib is mGraphicBuffer. The rest of the fields are added
@@ -37,6 +36,7 @@
enum { INVALID_BUFFER_SLOT = -1 };
BufferItem() : mGraphicBuffer(nullptr), mFence(Fence::NO_FENCE) {}
+
~BufferItem() {}
sp<GraphicBuffer> mGraphicBuffer;
@@ -60,6 +60,6 @@
bool mTransformToDisplayInverse;
};
-}
+} // namespace android
#endif // ANDROID_GUI_BUFFERITEM_H
diff --git a/libs/hostgraphics/gui/BufferItemConsumer.h b/libs/hostgraphics/gui/BufferItemConsumer.h
index 707b313..c259411 100644
--- a/libs/hostgraphics/gui/BufferItemConsumer.h
+++ b/libs/hostgraphics/gui/BufferItemConsumer.h
@@ -17,32 +17,30 @@
#ifndef ANDROID_GUI_BUFFERITEMCONSUMER_H
#define ANDROID_GUI_BUFFERITEMCONSUMER_H
-#include <utils/RefBase.h>
-
#include <gui/ConsumerBase.h>
#include <gui/IGraphicBufferConsumer.h>
+#include <utils/RefBase.h>
namespace android {
class BufferItemConsumer : public ConsumerBase {
public:
- BufferItemConsumer(
- const sp<IGraphicBufferConsumer>& consumer,
- uint64_t consumerUsage,
- int bufferCount,
- bool controlledByApp) : mConsumer(consumer) {
- }
+ BufferItemConsumer(const sp<IGraphicBufferConsumer>& consumer, uint64_t consumerUsage,
+ int bufferCount, bool controlledByApp)
+ : mConsumer(consumer) {}
- status_t acquireBuffer(BufferItem *item, nsecs_t presentWhen, bool waitForFence = true) {
+ status_t acquireBuffer(BufferItem* item, nsecs_t presentWhen, bool waitForFence = true) {
return mConsumer->acquireBuffer(item, presentWhen, 0);
}
- status_t releaseBuffer(
- const BufferItem &item, const sp<Fence>& releaseFence = Fence::NO_FENCE) { return OK; }
+ status_t releaseBuffer(const BufferItem& item,
+ const sp<Fence>& releaseFence = Fence::NO_FENCE) {
+ return OK;
+ }
- void setName(const String8& name) { }
+ void setName(const String8& name) {}
- void setFrameAvailableListener(const wp<FrameAvailableListener>& listener) { }
+ void setFrameAvailableListener(const wp<FrameAvailableListener>& listener) {}
status_t setDefaultBufferSize(uint32_t width, uint32_t height) {
return mConsumer->setDefaultBufferSize(width, height);
@@ -56,16 +54,23 @@
return mConsumer->setDefaultBufferDataSpace(defaultDataSpace);
}
- void abandon() { }
+ void abandon() {}
- status_t detachBuffer(int slot) { return OK; }
+ status_t detachBuffer(int slot) {
+ return OK;
+ }
- status_t discardFreeBuffers() { return OK; }
+ status_t discardFreeBuffers() {
+ return OK;
+ }
- void freeBufferLocked(int slotIndex) { }
+ void freeBufferLocked(int slotIndex) {}
- status_t addReleaseFenceLocked(
- int slot, const sp<GraphicBuffer> graphicBuffer, const sp<Fence>& fence) { return OK; }
+ status_t addReleaseFenceLocked(int slot, const sp<GraphicBuffer> graphicBuffer,
+ const sp<Fence>& fence) {
+ return OK;
+ }
+
private:
sp<IGraphicBufferConsumer> mConsumer;
};
diff --git a/libs/hostgraphics/gui/BufferQueue.h b/libs/hostgraphics/gui/BufferQueue.h
index aa3e726..67a8c00 100644
--- a/libs/hostgraphics/gui/BufferQueue.h
+++ b/libs/hostgraphics/gui/BufferQueue.h
@@ -29,7 +29,7 @@
enum { NO_BUFFER_AVAILABLE = IGraphicBufferConsumer::NO_BUFFER_AVAILABLE };
static void createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
- sp<IGraphicBufferConsumer>* outConsumer);
+ sp<IGraphicBufferConsumer>* outConsumer);
};
} // namespace android
diff --git a/libs/hostgraphics/gui/ConsumerBase.h b/libs/hostgraphics/gui/ConsumerBase.h
index 9002953..7f7309e 100644
--- a/libs/hostgraphics/gui/ConsumerBase.h
+++ b/libs/hostgraphics/gui/ConsumerBase.h
@@ -18,7 +18,6 @@
#define ANDROID_GUI_CONSUMERBASE_H
#include <gui/BufferItem.h>
-
#include <utils/RefBase.h>
namespace android {
@@ -28,10 +27,11 @@
struct FrameAvailableListener : public virtual RefBase {
// See IConsumerListener::onFrame{Available,Replaced}
virtual void onFrameAvailable(const BufferItem& item) = 0;
+
virtual void onFrameReplaced(const BufferItem& /* item */) {}
};
};
} // namespace android
-#endif // ANDROID_GUI_CONSUMERBASE_H
\ No newline at end of file
+#endif // ANDROID_GUI_CONSUMERBASE_H
diff --git a/libs/hostgraphics/gui/IGraphicBufferConsumer.h b/libs/hostgraphics/gui/IGraphicBufferConsumer.h
index 9eb67b2..14ac4fe 100644
--- a/libs/hostgraphics/gui/IGraphicBufferConsumer.h
+++ b/libs/hostgraphics/gui/IGraphicBufferConsumer.h
@@ -16,16 +16,16 @@
#pragma once
-#include <utils/RefBase.h>
-
#include <ui/PixelFormat.h>
-
#include <utils/Errors.h>
+#include <utils/RefBase.h>
namespace android {
class BufferItem;
+
class Fence;
+
class GraphicBuffer;
class IGraphicBufferConsumer : virtual public RefBase {
@@ -62,4 +62,4 @@
virtual status_t discardFreeBuffers() = 0;
};
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/libs/hostgraphics/gui/IGraphicBufferProducer.h b/libs/hostgraphics/gui/IGraphicBufferProducer.h
index 1447a4f..8fd8590 100644
--- a/libs/hostgraphics/gui/IGraphicBufferProducer.h
+++ b/libs/hostgraphics/gui/IGraphicBufferProducer.h
@@ -17,9 +17,8 @@
#ifndef ANDROID_GUI_IGRAPHICBUFFERPRODUCER_H
#define ANDROID_GUI_IGRAPHICBUFFERPRODUCER_H
-#include <utils/RefBase.h>
-
#include <ui/GraphicBuffer.h>
+#include <utils/RefBase.h>
namespace android {
diff --git a/libs/hostgraphics/gui/Surface.h b/libs/hostgraphics/gui/Surface.h
index 0d81037..2774f89 100644
--- a/libs/hostgraphics/gui/Surface.h
+++ b/libs/hostgraphics/gui/Surface.h
@@ -28,17 +28,25 @@
class Surface : public ANativeObjectBase<ANativeWindow, Surface, RefBase> {
public:
explicit Surface(const sp<IGraphicBufferProducer>& bufferProducer, bool controlledByApp = false)
- : mBufferProducer(bufferProducer) {
+ : mBufferProducer(bufferProducer) {
ANativeWindow::perform = hook_perform;
ANativeWindow::dequeueBuffer = hook_dequeueBuffer;
ANativeWindow::query = hook_query;
}
- static bool isValid(const sp<Surface>& surface) { return surface != nullptr; }
+
+ static bool isValid(const sp<Surface>& surface) {
+ return surface != nullptr;
+ }
+
void allocateBuffers() {}
- uint64_t getNextFrameNumber() const { return 0; }
+ uint64_t getNextFrameNumber() const {
+ return 0;
+ }
- int setScalingMode(int mode) { return 0; }
+ int setScalingMode(int mode) {
+ return 0;
+ }
virtual int disconnect(int api,
IGraphicBufferProducer::DisconnectMode mode =
@@ -50,16 +58,28 @@
// TODO: implement this
return 0;
}
- virtual int unlockAndPost() { return 0; }
- virtual int query(int what, int* value) const { return mBufferProducer->query(what, value); }
- status_t setDequeueTimeout(nsecs_t timeout) { return OK; }
+ virtual int unlockAndPost() {
+ return 0;
+ }
- nsecs_t getLastDequeueStartTime() const { return 0; }
+ virtual int query(int what, int* value) const {
+ return mBufferProducer->query(what, value);
+ }
+
+ status_t setDequeueTimeout(nsecs_t timeout) {
+ return OK;
+ }
+
+ nsecs_t getLastDequeueStartTime() const {
+ return 0;
+ }
virtual void destroy() {}
- int getBuffersDataSpace() { return 0; }
+ int getBuffersDataSpace() {
+ return 0;
+ }
protected:
virtual ~Surface() {}
@@ -89,15 +109,31 @@
*buffer = mBuffer.get();
return OK;
}
- virtual int cancelBuffer(ANativeWindowBuffer* buffer, int fenceFd) { return 0; }
- virtual int queueBuffer(ANativeWindowBuffer* buffer, int fenceFd) { return 0; }
- virtual int perform(int operation, va_list args) { return 0; }
- virtual int setSwapInterval(int interval) { return 0; }
- virtual int setBufferCount(int bufferCount) { return 0; }
+
+ virtual int cancelBuffer(ANativeWindowBuffer* buffer, int fenceFd) {
+ return 0;
+ }
+
+ virtual int queueBuffer(ANativeWindowBuffer* buffer, int fenceFd) {
+ return 0;
+ }
+
+ virtual int perform(int operation, va_list args) {
+ return 0;
+ }
+
+ virtual int setSwapInterval(int interval) {
+ return 0;
+ }
+
+ virtual int setBufferCount(int bufferCount) {
+ return 0;
+ }
private:
// can't be copied
Surface& operator=(const Surface& rhs);
+
Surface(const Surface& rhs);
const sp<IGraphicBufferProducer> mBufferProducer;
@@ -106,4 +142,4 @@
} // namespace android
-#endif // ANDROID_GUI_SURFACE_H
+#endif // ANDROID_GUI_SURFACE_H
diff --git a/libs/hostgraphics/ui/Fence.h b/libs/hostgraphics/ui/Fence.h
index 04d535c..187c311 100644
--- a/libs/hostgraphics/ui/Fence.h
+++ b/libs/hostgraphics/ui/Fence.h
@@ -17,8 +17,8 @@
#ifndef ANDROID_FENCE_H
#define ANDROID_FENCE_H
-#include <utils/String8.h>
#include <utils/RefBase.h>
+#include <utils/String8.h>
typedef int64_t nsecs_t;
@@ -26,11 +26,14 @@
class Fence : public LightRefBase<Fence> {
public:
- Fence() { }
- Fence(int) { }
+ Fence() {}
+
+ Fence(int) {}
+
static const sp<Fence> NO_FENCE;
static constexpr nsecs_t SIGNAL_TIME_PENDING = INT64_MAX;
static constexpr nsecs_t SIGNAL_TIME_INVALID = -1;
+
static sp<Fence> merge(const char* name, const sp<Fence>& f1, const sp<Fence>& f2) {
return NO_FENCE;
}
@@ -40,16 +43,22 @@
}
enum class Status {
- Invalid, // Fence is invalid
- Unsignaled, // Fence is valid but has not yet signaled
- Signaled, // Fence is valid and has signaled
+ Invalid, // Fence is invalid
+ Unsignaled, // Fence is valid but has not yet signaled
+ Signaled, // Fence is valid and has signaled
};
- status_t wait(int timeout) { return OK; }
+ status_t wait(int timeout) {
+ return OK;
+ }
- status_t waitForever(const char* logname) { return OK; }
+ status_t waitForever(const char* logname) {
+ return OK;
+ }
- int dup() const { return 0; }
+ int dup() const {
+ return 0;
+ }
inline Status getStatus() {
// The sync_wait call underlying wait() has been measured to be
diff --git a/libs/hostgraphics/ui/GraphicBuffer.h b/libs/hostgraphics/ui/GraphicBuffer.h
index eec9b23..cda45e46 100644
--- a/libs/hostgraphics/ui/GraphicBuffer.h
+++ b/libs/hostgraphics/ui/GraphicBuffer.h
@@ -19,34 +19,51 @@
#include <stdint.h>
#include <sys/types.h>
-
-#include <vector>
-
#include <ui/ANativeObjectBase.h>
#include <ui/PixelFormat.h>
#include <ui/Rect.h>
#include <utils/RefBase.h>
+#include <vector>
+
namespace android {
class GraphicBuffer : public ANativeObjectBase<ANativeWindowBuffer, GraphicBuffer, RefBase> {
public:
GraphicBuffer(uint32_t w, uint32_t h) {
- data.resize(w*h);
+ data.resize(w * h);
reserved[0] = data.data();
width = w;
height = h;
}
- uint32_t getWidth() const { return static_cast<uint32_t>(width); }
- uint32_t getHeight() const { return static_cast<uint32_t>(height); }
- uint32_t getStride() const { return static_cast<uint32_t>(width); }
- uint64_t getUsage() const { return 0; }
- PixelFormat getPixelFormat() const { return PIXEL_FORMAT_RGBA_8888; }
- Rect getBounds() const { return Rect(width, height); }
+ uint32_t getWidth() const {
+ return static_cast<uint32_t>(width);
+ }
- status_t lockAsyncYCbCr(uint32_t inUsage, const Rect& rect,
- android_ycbcr *ycbcr, int fenceFd) { return OK; }
+ uint32_t getHeight() const {
+ return static_cast<uint32_t>(height);
+ }
+
+ uint32_t getStride() const {
+ return static_cast<uint32_t>(width);
+ }
+
+ uint64_t getUsage() const {
+ return 0;
+ }
+
+ PixelFormat getPixelFormat() const {
+ return PIXEL_FORMAT_RGBA_8888;
+ }
+
+ Rect getBounds() const {
+ return Rect(width, height);
+ }
+
+ status_t lockAsyncYCbCr(uint32_t inUsage, const Rect& rect, android_ycbcr* ycbcr, int fenceFd) {
+ return OK;
+ }
status_t lockAsync(uint32_t inUsage, const Rect& rect, void** vaddr, int fenceFd,
int32_t* outBytesPerPixel = nullptr, int32_t* outBytesPerStride = nullptr) {
@@ -54,7 +71,9 @@
return OK;
}
- status_t unlockAsync(int *fenceFd) { return OK; }
+ status_t unlockAsync(int* fenceFd) {
+ return OK;
+ }
private:
std::vector<uint32_t> data;
diff --git a/media/java/android/media/RingtoneManager.java b/media/java/android/media/RingtoneManager.java
index 3432b3f..86113df 100644
--- a/media/java/android/media/RingtoneManager.java
+++ b/media/java/android/media/RingtoneManager.java
@@ -16,7 +16,6 @@
package android.media;
-import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
@@ -573,12 +572,13 @@
FileUtils.closeQuietly(cursor);
throw new FileNotFoundException("No item found for " + baseUri);
} else if (cursor.getCount() > 1) {
+ int resultCount = cursor.getCount();
// Find more than 1 result.
// We are not sure which one is the right ringtone file so just abandon this case.
FileUtils.closeQuietly(cursor);
throw new FileNotFoundException(
"Find multiple ringtone candidates by title+ringtone_type query: count: "
- + cursor.getCount());
+ + resultCount);
}
if (cursor.moveToFirst()) {
ringtoneUri = ContentUris.withAppendedId(baseUri, cursor.getLong(0));
diff --git a/packages/SettingsLib/FooterPreference/src/com/android/settingslib/widget/FooterPreference.java b/packages/SettingsLib/FooterPreference/src/com/android/settingslib/widget/FooterPreference.java
index 5b2fa1d..05507e0 100644
--- a/packages/SettingsLib/FooterPreference/src/com/android/settingslib/widget/FooterPreference.java
+++ b/packages/SettingsLib/FooterPreference/src/com/android/settingslib/widget/FooterPreference.java
@@ -17,10 +17,15 @@
package com.android.settingslib.widget;
import android.content.Context;
+import android.content.Intent;
import android.text.SpannableString;
+import android.text.Spanned;
import android.text.TextUtils;
+import android.text.method.LinkMovementMethod;
+import android.text.style.ClickableSpan;
import android.text.style.URLSpan;
import android.util.AttributeSet;
+import android.util.Log;
import android.view.View;
import android.widget.TextView;
@@ -32,18 +37,20 @@
import com.android.settingslib.widget.preference.footer.R;
+import java.net.URISyntaxException;
+
/**
* A custom preference acting as "footer" of a page. It has a field for icon and text. It is added
* to screen as the last preference.
*/
public class FooterPreference extends Preference {
+ private static final String TAG = "FooterPreference";
public static final String KEY_FOOTER = "footer_preference";
+ private static final String INTENT_URL_PREFIX = "intent:";
static final int ORDER_FOOTER = Integer.MAX_VALUE - 1;
- @VisibleForTesting
- View.OnClickListener mLearnMoreListener;
- @VisibleForTesting
- int mIconVisibility = View.VISIBLE;
+ @VisibleForTesting View.OnClickListener mLearnMoreListener;
+ @VisibleForTesting int mIconVisibility = View.VISIBLE;
private CharSequence mContentDescription;
private CharSequence mLearnMoreText;
private FooterLearnMoreSpan mLearnMoreSpan;
@@ -57,12 +64,56 @@
this(context, null);
}
+ private void linkifyTitle(TextView title) {
+ final CharSequence text = getTitle();
+ if (!(text instanceof Spanned)) {
+ return;
+ }
+ final ClickableSpan[] spans =
+ ((Spanned) text).getSpans(0, text.length(), ClickableSpan.class);
+ if (spans.length == 0) {
+ return;
+ }
+ SpannableString spannable = new SpannableString(text);
+ for (ClickableSpan clickable : spans) {
+ if (!(clickable instanceof URLSpan)) {
+ continue;
+ }
+ final URLSpan urlSpan = (URLSpan) clickable;
+ if (!urlSpan.getURL().startsWith(INTENT_URL_PREFIX)) {
+ continue;
+ }
+ final int start = spannable.getSpanStart(urlSpan);
+ final int end = spannable.getSpanEnd(urlSpan);
+ spannable.removeSpan(urlSpan);
+ try {
+ final Intent intent = Intent.parseUri(urlSpan.getURL(), Intent.URI_INTENT_SCHEME);
+ final ClickableSpan clickableSpan =
+ new ClickableSpan() {
+ @Override
+ public void onClick(@NonNull View textView) {
+ // May throw ActivityNotFoundException. Just let it propagate.
+ getContext().startActivity(intent);
+ }
+ };
+ spannable.setSpan(clickableSpan, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+ } catch (URISyntaxException e) {
+ Log.e(TAG, "Invalid URI " + urlSpan.getURL(), e);
+ }
+ }
+ title.setText(spannable);
+ title.setMovementMethod(LinkMovementMethod.getInstance());
+ }
+
@Override
public void onBindViewHolder(PreferenceViewHolder holder) {
super.onBindViewHolder(holder);
TextView title = holder.itemView.findViewById(android.R.id.title);
- if (title != null && !TextUtils.isEmpty(mContentDescription)) {
- title.setContentDescription(mContentDescription);
+ if (title != null) {
+ if (!TextUtils.isEmpty(mContentDescription)) {
+ title.setContentDescription(mContentDescription);
+ }
+ linkifyTitle(title);
}
TextView learnMore = holder.itemView.findViewById(R.id.settingslib_learn_more);
@@ -79,8 +130,7 @@
learnMoreText.removeSpan(mLearnMoreSpan);
}
mLearnMoreSpan = new FooterLearnMoreSpan(mLearnMoreListener);
- learnMoreText.setSpan(mLearnMoreSpan, 0,
- learnMoreText.length(), 0);
+ learnMoreText.setSpan(mLearnMoreSpan, 0, learnMoreText.length(), 0);
learnMore.setText(learnMoreText);
} else {
learnMore.setVisibility(View.GONE);
@@ -121,9 +171,7 @@
}
}
- /**
- * Return the content description of footer preference.
- */
+ /** Return the content description of footer preference. */
@VisibleForTesting
CharSequence getContentDescription() {
return mContentDescription;
@@ -141,9 +189,7 @@
}
}
- /**
- * Assign an action for the learn more link.
- */
+ /** Assign an action for the learn more link. */
public void setLearnMoreAction(View.OnClickListener listener) {
if (mLearnMoreListener != listener) {
mLearnMoreListener = listener;
@@ -151,9 +197,7 @@
}
}
- /**
- * Set visibility of footer icon.
- */
+ /** Set visibility of footer icon. */
public void setIconVisibility(int iconVisibility) {
if (mIconVisibility == iconVisibility) {
return;
@@ -174,9 +218,7 @@
setSelectable(false);
}
- /**
- * The builder is convenient to creat a dynamic FooterPreference.
- */
+ /** The builder is convenient to creat a dynamic FooterPreference. */
public static class Builder {
private Context mContext;
private String mKey;
@@ -241,8 +283,8 @@
}
/**
- * To set learn more string of the learn more text. This can use for talkback
- * environment if developer wants to have a customization content.
+ * To set learn more string of the learn more text. This can use for talkback environment if
+ * developer wants to have a customization content.
*
* @param learnMoreText The resource id of the learn more string.
*/
@@ -262,10 +304,7 @@
return this;
}
-
- /**
- * To generate the {@link FooterPreference}.
- */
+ /** To generate the {@link FooterPreference}. */
public FooterPreference build() {
final FooterPreference footerPreference = new FooterPreference(mContext);
footerPreference.setSelectable(false);
@@ -288,9 +327,7 @@
}
}
- /**
- * A {@link URLSpan} that opens a support page when clicked
- */
+ /** A {@link URLSpan} that opens a support page when clicked */
static class FooterLearnMoreSpan extends URLSpan {
private final View.OnClickListener mClickListener;
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 73c96d9..1515811 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -201,9 +201,9 @@
<!-- Connected devices settings. Message when Bluetooth is connected and active, showing remote device status and battery level for untethered headset. [CHAR LIMIT=NONE] -->
<string name="bluetooth_active_battery_level_untethered">Active. L: <xliff:g id="battery_level_as_percentage" example="25%">%1$s</xliff:g>, R: <xliff:g id="battery_level_as_percentage" example="25%">%2$s</xliff:g> battery.</string>
<!-- Connected devices settings. Message when Bluetooth is connected and active, showing remote device status and battery level for the left part of the untethered headset. [CHAR LIMIT=NONE] -->
- <string name="bluetooth_active_battery_level_untethered_left">Active. L: <xliff:g id="battery_level_as_percentage" example="25%">%1$s</xliff:g> battery</string>
+ <string name="bluetooth_active_battery_level_untethered_left">Active. L: <xliff:g id="battery_level_as_percentage" example="25%">%1$s</xliff:g> battery.</string>
<!-- Connected devices settings. Message when Bluetooth is connected and active, showing remote device status and battery level for the right part of the untethered headset. [CHAR LIMIT=NONE] -->
- <string name="bluetooth_active_battery_level_untethered_right">Active. R: <xliff:g id="battery_level_as_percentage" example="25%">%1$s</xliff:g> battery</string>
+ <string name="bluetooth_active_battery_level_untethered_right">Active. R: <xliff:g id="battery_level_as_percentage" example="25%">%1$s</xliff:g> battery.</string>
<!-- Connected devices settings. Message when Bluetooth is connected but not in use, showing remote device battery level. [CHAR LIMIT=NONE] -->
<string name="bluetooth_battery_level"><xliff:g id="battery_level_as_percentage">%1$s</xliff:g> battery</string>
<!-- Connected devices settings. Message on TV when Bluetooth is connected but not in use, showing remote device battery level. [CHAR LIMIT=NONE] -->
@@ -220,11 +220,11 @@
<string name="bluetooth_saved_device">Saved</string>
<!-- Connected device settings. Message when the left-side hearing aid device is active. [CHAR LIMIT=NONE] -->
- <string name="bluetooth_hearing_aid_left_active">Active, left only</string>
+ <string name="bluetooth_hearing_aid_left_active">Active (left only)</string>
<!-- Connected device settings. Message when the right-side hearing aid device is active. [CHAR LIMIT=NONE] -->
- <string name="bluetooth_hearing_aid_right_active">Active, right only</string>
+ <string name="bluetooth_hearing_aid_right_active">Active (right only)</string>
<!-- Connected device settings. Message when the left-side and right-side hearing aids device are active. [CHAR LIMIT=NONE] -->
- <string name="bluetooth_hearing_aid_left_and_right_active">Active, left and right</string>
+ <string name="bluetooth_hearing_aid_left_and_right_active">Active (left and right)</string>
<!-- Connected devices settings. Message when Bluetooth is connected and active for media only, showing remote device status and battery level. [CHAR LIMIT=NONE] -->
<string name="bluetooth_active_media_only_battery_level">Active (media only). <xliff:g id="battery_level_as_percentage">%1$s</xliff:g> battery.</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
index 06c41cb..fd9a008 100644
--- a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
@@ -2131,7 +2131,13 @@
public boolean filterApp(AppEntry entry) {
return !AppUtils.isInstant(entry.info)
&& hasFlag(entry.info.privateFlags,
- ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS);
+ ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS)
+ && !entry.hideInQuietMode;
+ }
+
+ @Override
+ public void refreshAppEntryOnRebuild(@NonNull AppEntry appEntry, boolean hideInQuietMode) {
+ appEntry.hideInQuietMode = hideInQuietMode;
}
};
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
index c13c493..b356f54 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
@@ -697,7 +697,7 @@
// Set device as Active for Hearing Aid and test connection state summary
mCachedDevice.setHearingAidInfo(getLeftAshaHearingAidInfo());
mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.HEARING_AID);
- assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Active, left only");
+ assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Active (left only)");
// Set Hearing Aid profile to be disconnected and test connection state summary
mCachedDevice.onActiveDeviceChanged(false, BluetoothProfile.HEARING_AID);
@@ -717,7 +717,7 @@
mCachedDevice.setHearingAidInfo(getLeftAshaHearingAidInfo());
mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.HEARING_AID);
assertThat(mCachedDevice.getTvConnectionSummary().toString()).isEqualTo(
- "Active, left only");
+ "Active (left only)");
// Set Hearing Aid profile to be disconnected and test connection state summary
mCachedDevice.onActiveDeviceChanged(false, BluetoothProfile.HEARING_AID);
@@ -794,7 +794,7 @@
// Act & Assert:
// Get "Active" result without Battery Level.
- assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Active, right only");
+ assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Active (right only)");
}
@Test
@@ -810,7 +810,7 @@
// Act & Assert:
// Get "Active" result without Battery Level.
assertThat(mCachedDevice.getTvConnectionSummary().toString()).isEqualTo(
- "Active, right only");
+ "Active (right only)");
}
@Test
@@ -828,7 +828,7 @@
// Act & Assert:
// Get "Active" result without Battery Level.
- assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Active, left and right");
+ assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Active (left and right)");
}
@Test
@@ -847,7 +847,7 @@
// Act & Assert:
// Get "Active" result without Battery Level.
assertThat(mCachedDevice.getTvConnectionSummary().toString())
- .isEqualTo("Active, left and right");
+ .isEqualTo("Active (left and right)");
}
@Test
@@ -894,7 +894,7 @@
// Set device as Active for LE Audio and test connection state summary
mCachedDevice.setHearingAidInfo(getLeftLeAudioHearingAidInfo());
mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.LE_AUDIO);
- assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Active, left only");
+ assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Active (left only)");
// Set LE Audio profile to be disconnected and test connection state summary
mCachedDevice.onActiveDeviceChanged(false, BluetoothProfile.LE_AUDIO);
@@ -915,7 +915,7 @@
mCachedDevice.setHearingAidInfo(getLeftLeAudioHearingAidInfo());
mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.LE_AUDIO);
assertThat(mCachedDevice.getTvConnectionSummary().toString()).isEqualTo(
- "Active, left only");
+ "Active (left only)");
// Set LE Audio profile to be disconnected and test connection state summary
mCachedDevice.onActiveDeviceChanged(false, BluetoothProfile.LE_AUDIO);
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
index 75c0cec..9d02074 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
@@ -273,6 +273,7 @@
Settings.Secure.AUDIO_DEVICE_INVENTORY,
Settings.Secure.SCREEN_RESOLUTION_MODE,
Settings.Secure.ACCESSIBILITY_FLOATING_MENU_TARGETS,
- Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_SATURATION_LEVEL
+ Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_SATURATION_LEVEL,
+ Settings.Secure.CHARGE_OPTIMIZATION_MODE
};
}
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
index 8faf917..6cb9d50 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -432,5 +432,6 @@
Secure.RESOLUTION_MODE_UNKNOWN, Secure.RESOLUTION_MODE_FULL));
VALIDATORS.put(Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_SATURATION_LEVEL,
new InclusiveIntegerRangeValidator(0, 10));
+ VALIDATORS.put(Secure.CHARGE_OPTIMIZATION_MODE, new InclusiveIntegerRangeValidator(0, 10));
}
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index fa9b279..52e9b6d5 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -2745,6 +2745,9 @@
dumpSetting(s, p,
Settings.Secure.ZEN_SETTINGS_SUGGESTION_VIEWED,
SecureSettingsProto.Zen.SETTINGS_SUGGESTION_VIEWED);
+ dumpSetting(s, p,
+ Settings.Secure.CHARGE_OPTIMIZATION_MODE,
+ SecureSettingsProto.CHARGE_OPTIMIZATION_MODE);
p.end(zenToken);
// Please insert new settings using the same order as in SecureSettingsProto.
diff --git a/packages/SoundPicker/AndroidManifest.xml b/packages/SoundPicker/AndroidManifest.xml
index 44295a5..98fee5b 100644
--- a/packages/SoundPicker/AndroidManifest.xml
+++ b/packages/SoundPicker/AndroidManifest.xml
@@ -9,6 +9,8 @@
<uses-permission android:name="android.permission.RECEIVE_DEVICE_CUSTOMIZATION_READY" />
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
+ <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
+
<application
android:allowBackup="false"
android:label="@string/app_label"
diff --git a/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/gloweffect/GlowPieEffect.kt b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/gloweffect/GlowPieEffect.kt
deleted file mode 100644
index c08afd3..0000000
--- a/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/gloweffect/GlowPieEffect.kt
+++ /dev/null
@@ -1,209 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.surfaceeffects.gloweffect
-
-import android.animation.ValueAnimator
-import android.animation.ValueAnimator.INFINITE
-import android.graphics.RenderEffect
-import androidx.annotation.VisibleForTesting
-import com.android.systemui.surfaceeffects.RenderEffectDrawCallback
-import com.android.systemui.surfaceeffects.utils.MathUtils
-
-/** Renders rotating pie with glow on top, masked with a rounded box. */
-class GlowPieEffect(
- config: GlowPieEffectConfig,
- private val renderEffectDrawCallback: RenderEffectDrawCallback
-) {
-
- private val glowPieShader = GlowPieShader().apply { applyConfig(config) }
-
- @VisibleForTesting
- val mainAnimator: ValueAnimator =
- ValueAnimator.ofFloat(0f, 1f).apply {
- // We want to loop the full cycle.
- duration = DURATION_MS
- repeatMode = ValueAnimator.RESTART
- repeatCount = INFINITE
- }
-
- /** Plays glow pie until [finish] is called. */
- fun play() {
- if (mainAnimator.isRunning) return
-
- baseGlow.resetProgress()
- firstGlowPie.resetProgress()
- secondGlowPie.resetProgress()
-
- mainAnimator.addUpdateListener { updateListener ->
- val time = updateListener.currentPlayTime.toFloat() % mainAnimator.duration
-
- // Remap each glow pie progress.
- baseGlow.updateProgress(time)
- firstGlowPie.updateProgress(time)
- secondGlowPie.updateProgress(time)
-
- // TODO(b/335315940): Consider passing in 2D Matrix.
- glowPieShader.setAngles(baseGlow.angle(), firstGlowPie.angle(), secondGlowPie.angle())
- glowPieShader.setBottomAngleThresholds(
- baseGlow.bottomThreshold(),
- firstGlowPie.bottomThreshold(),
- secondGlowPie.bottomThreshold()
- )
- glowPieShader.setTopAngleThresholds(
- baseGlow.topThreshold(),
- firstGlowPie.topThreshold(),
- secondGlowPie.topThreshold()
- )
- glowPieShader.setAlphas(baseGlow.alpha(), firstGlowPie.alpha(), secondGlowPie.alpha())
-
- // Finally trigger the draw callback.
- renderEffectDrawCallback.onDraw(
- RenderEffect.createRuntimeShaderEffect(
- glowPieShader,
- GlowPieShader.BACKGROUND_UNIFORM
- )
- )
- }
-
- mainAnimator.start()
- }
-
- fun finish() {
- // TODO(b/335315940) Add alpha fade.
- mainAnimator.cancel()
- }
-
- companion object {
- @VisibleForTesting const val PI = Math.PI.toFloat()
- @VisibleForTesting const val FEATHER = 0.3f
- @VisibleForTesting const val DURATION_MS = 3000L
-
- private val baseGlow = BaseGlow()
- private val firstGlowPie = FirstGlowPie()
- private val secondGlowPie = SecondGlowPie()
- }
-
- /** Contains animation parameters for each layer of glow pie. */
- interface GlowPie {
- /**
- * The start & end timestamps of the animation. Must be smaller than or equal to the full
- * [DURATION_MS].
- */
- val startMs: Float
- val endMs: Float
- /**
- * Start & end angles in radian. This determines how many cycles you want to rotate. e.g.
- * startAngle = 0f endAngle = 4f * PI, will give you the 2 cycles.
- */
- val startAngle: Float
- val endAngle: Float
- /**
- * Start & end timestamps of the fade out duration. You may want to override [alpha] if you
- * want to make it fade in. See [BaseGlow].
- */
- val alphaFadeStartMs: Float
- val alphaFadeEndMs: Float
-
- /** Below two values are expected to be updated through [updateProgress]. */
- /** Normalized progress. */
- var progress: Float
- /** current time of the animation in ms. */
- var time: Float
-
- // Must be called before retrieving angle, bottom & top thresholds, and alpha.
- // Otherwise the values would be stale.
- fun updateProgress(time: Float) {
- progress = MathUtils.constrainedMap(0f, 1f, startMs, endMs, time)
- this.time = time
- }
-
- fun resetProgress() {
- progress = 0f
- time = 0f
- }
-
- fun angle(): Float {
- // Negate the angle since we want clock-wise rotation.
- val angle =
- MathUtils.constrainedMap(startAngle, endAngle, 0f, 1f, progress) + progress * PI
- return -angle
- }
-
- fun bottomThreshold(): Float {
- return MathUtils.lerp(1f, -FEATHER, progress)
- }
-
- fun topThreshold(): Float {
- return MathUtils.lerp(1f + FEATHER, 0f, progress)
- }
-
- // By default, it fades "out".
- fun alpha(): Float {
- // Remap timestamps (in MS) to alpha [0, 1].
- return MathUtils.constrainedMap(1f, 0f, alphaFadeStartMs, alphaFadeEndMs, time)
- }
- }
-
- data class BaseGlow(
- override val startMs: Float = 0f,
- override val endMs: Float = 0f,
- override val startAngle: Float = 0f,
- override val endAngle: Float = 0f,
- override val alphaFadeStartMs: Float = 2250f,
- override val alphaFadeEndMs: Float = 2950f,
- ) : GlowPie {
-
- override var progress: Float = 1f
- override var time: Float = 0f
- override fun updateProgress(time: Float) {}
-
- override fun resetProgress() {}
-
- override fun angle(): Float = 0f
-
- override fun bottomThreshold(): Float = 0f
-
- override fun topThreshold(): Float = 0f
-
- // Base glow fade "in" (i.e. reveals).
- override fun alpha(): Float {
- return MathUtils.constrainedMap(0f, 1f, alphaFadeStartMs, alphaFadeEndMs, time)
- }
- }
-
- data class FirstGlowPie(
- override val startMs: Float = 250f,
- override val endMs: Float = 2500f,
- override val startAngle: Float = -PI / 2f,
- override val endAngle: Float = 4f * PI,
- override val alphaFadeStartMs: Float = 2500f,
- override val alphaFadeEndMs: Float = 2750f,
- override var progress: Float = 0f,
- override var time: Float = 0f
- ) : GlowPie
-
- data class SecondGlowPie(
- override val startMs: Float = 350f,
- override val endMs: Float = 2600f,
- override val startAngle: Float = -PI / 2f,
- override val endAngle: Float = 3f * PI,
- override val alphaFadeStartMs: Float = 2600f,
- override val alphaFadeEndMs: Float = 2850f,
- override var progress: Float = 0f,
- override var time: Float = 0f
- ) : GlowPie
-}
diff --git a/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/gloweffect/GlowPieEffectConfig.kt b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/gloweffect/GlowPieEffectConfig.kt
deleted file mode 100644
index 6c728c1..0000000
--- a/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/gloweffect/GlowPieEffectConfig.kt
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.surfaceeffects.gloweffect
-
-/** Parameter values needed to draw [GlowPieEffect]. */
-data class GlowPieEffectConfig(
- /** Center x position of the effect. */
- val centerX: Float,
- /** Center y position of the effect. */
- val centerY: Float,
- /** Width of the rounded box mask. */
- val width: Float,
- /** Height of the rounded box mask. */
- val height: Float,
- /** Corner radius of the rounded box mask. */
- val cornerRadius: Float,
- /**
- * Colors of the effect. The number must match 3, which is defined in [GlowPieShader.NUM_PIE].
- * Each color corresponds to baseColor (bottom), firstLayerColor, and secondLayerColor (top).
- */
- val colors: IntArray
-)
diff --git a/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/gloweffect/GlowPieShader.kt b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/gloweffect/GlowPieShader.kt
deleted file mode 100644
index 2dbc0b5..0000000
--- a/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/gloweffect/GlowPieShader.kt
+++ /dev/null
@@ -1,233 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.surfaceeffects.gloweffect
-
-import android.graphics.RuntimeShader
-import android.util.Log
-import com.android.systemui.surfaceeffects.shaderutil.SdfShaderLibrary
-import com.android.systemui.surfaceeffects.shaderutil.ShaderUtilLibrary
-
-/** Draws two glowing pies rotating around the center of a rounded box on a base. */
-class GlowPieShader : RuntimeShader(GLOW_PIE_SHADER_COMP) {
- // language=AGSL
- companion object {
- const val BACKGROUND_UNIFORM = "in_dst"
- const val NUM_PIE = 3
-
- private const val UNIFORMS =
- """
- uniform shader ${BACKGROUND_UNIFORM};
- uniform vec2 in_center;
- uniform vec2 in_size;
- uniform half in_cornerRad;
- uniform float[${NUM_PIE}] in_angles;
- uniform float[${NUM_PIE}] in_alphas;
- uniform float[${NUM_PIE}] in_bottomThresholds;
- uniform float[${NUM_PIE}] in_topThresholds;
- layout(color) uniform vec4 in_colors0;
- layout(color) uniform vec4 in_colors1;
- layout(color) uniform vec4 in_colors2;
- """
-
- private const val GLOW_PIE_MAIN =
- """
- vec4 main(vec2 p) {
- vec4 pie = vec4(0.);
- vec4 glow = vec4(0.);
-
- vec2 c = p - in_center;
- half box = sdRoundedBox(c, in_size, in_cornerRad);
-
- // Base glow (drawn at the bottom)
- pieGlow(
- box,
- c,
- in_angles[0],
- in_colors0.rgb,
- /* pieAlpha= */ 1., // We always show the base color.
- /* glowAlpha= */ in_alphas[0],
- vec2(in_bottomThresholds[0], in_topThresholds[0]),
- pie,
- glow
- );
-
- // First pie
- pieGlow(
- box,
- c,
- in_angles[1],
- in_colors1.rgb,
- /* pieAlpha= */ in_alphas[1],
- /* glowAlpha= */ in_alphas[1],
- vec2(in_bottomThresholds[1], in_topThresholds[1]),
- pie,
- glow
- );
-
- // Second pie (drawn on top)
- pieGlow(
- box,
- c,
- in_angles[2],
- in_colors2.rgb,
- /* pieAlpha= */ in_alphas[2],
- /* glowAlpha= */ in_alphas[2],
- vec2(in_bottomThresholds[2], in_topThresholds[2]),
- pie,
- glow
- );
-
- return vec4(pie.rgb + glow.rgb * 0.3, pie.a);
- }
- """
-
- private const val REMAP =
- """
- float remap(float in_start, float in_end, float out_start, float out_end, float x) {
- x = (x - in_start) / (in_end - in_start);
- x = clamp(x, 0., 1.);
- return x * (out_end - out_start) + out_start;
- }
- """
-
- /**
- * This function draws a pie slice, an a glow on top. The glow also has the same pie shape
- * but with more blur and additive blending.
- */
- private const val GLOW_PIE =
- """
- void pieGlow(
- half box,
- vec2 c,
- half angle,
- vec3 color,
- half pieAlpha,
- half glowAlpha,
- vec2 angleThresholds,
- inout vec4 inout_pie,
- inout vec4 inout_glow) {
-
- // Apply angular rotation.
- half co = cos(angle), si = sin(angle);
- mat2 rotM = mat2(co, -si, si, co); // 2D rotation matrix
- c *= rotM;
-
- // We rotate based on the cosine value, since we want to avoid using inverse
- // trig function, which in this case is atan.
-
- // Dot product with vec2(1., 0.) and bring the range to [0,1].
- // Same as dot(normalize(c), vec2(1.,0) * 0.5 + 0.5
- half d = normalize(c).x * 0.5 + 0.5;
-
- // Those thresholds represents each end of the pie.
- float bottomThreshold = angleThresholds[0];
- float topThreshold = angleThresholds[1];
- float angleMask = remap(bottomThreshold, topThreshold, 0., 1., d);
-
- half boxMask = 1. - smoothstep(-0.02, 0.02, box);
- vec4 pie = vec4(color, 1.0) * angleMask * boxMask * pieAlpha;
-
- // We are drawing the same pie but with more blur.
- half glowMask = 1. - smoothstep(0., 0.6, box);
- // Glow outside only.
- glowMask = min(glowMask, smoothstep(-0.02, 0.02, box));
- // Apply some curve for the glow. (Can take out)
- glowMask *= glowMask * glowMask;
- // Glow mask should also be sliced with the angle mask.
- glowMask *= angleMask;
- vec4 glow = vec4(color, 1.0) * glowMask * glowAlpha;
-
- inout_pie = pie + inout_pie * (1. - pie.a);
- // Additive blending.
- inout_glow += glow;
- }
- """
-
- private const val GLOW_PIE_SHADER_COMP =
- ShaderUtilLibrary.SHADER_LIB +
- SdfShaderLibrary.SHADER_SDF_OPERATION_LIB +
- SdfShaderLibrary.ROUNDED_BOX_SDF +
- UNIFORMS +
- REMAP +
- GLOW_PIE +
- GLOW_PIE_MAIN
-
- private val TAG = GlowPieShader::class.java.simpleName
- }
-
- fun applyConfig(config: GlowPieEffectConfig) {
- setCenter(config.centerX, config.centerY)
- setSize(config.width, config.height)
- setCornerRadius(config.cornerRadius)
- setColor(config.colors)
- }
-
- fun setCenter(centerX: Float, centerY: Float) {
- setFloatUniform("in_center", centerX, centerY)
- }
-
- fun setSize(width: Float, height: Float) {
- setFloatUniform("in_size", width, height)
- }
-
- fun setCornerRadius(cornerRadius: Float) {
- setFloatUniform("in_cornerRad", cornerRadius)
- }
-
- /** Ignores alpha value, as fade in/out is handled within shader. */
- fun setColor(colors: IntArray) {
- if (colors.size != NUM_PIE) {
- Log.wtf(TAG, "The number of colors must be $NUM_PIE")
- return
- }
- setColorUniform("in_colors0", colors[0])
- setColorUniform("in_colors1", colors[1])
- setColorUniform("in_colors2", colors[2])
- }
-
- fun setAngles(vararg angles: Float) {
- if (angles.size != NUM_PIE) {
- Log.wtf(TAG, "The number of angles must be $NUM_PIE")
- return
- }
- setFloatUniform("in_angles", angles)
- }
-
- fun setAlphas(vararg alphas: Float) {
- if (alphas.size != NUM_PIE) {
- Log.wtf(TAG, "The number of angles must be $NUM_PIE")
- return
- }
- setFloatUniform("in_alphas", alphas)
- }
-
- fun setBottomAngleThresholds(vararg bottomThresholds: Float) {
- if (bottomThresholds.size != NUM_PIE) {
- Log.wtf(TAG, "The number of bottomThresholds must be $NUM_PIE")
- return
- }
- setFloatUniform("in_bottomThresholds", bottomThresholds)
- }
-
- fun setTopAngleThresholds(vararg topThresholds: Float) {
- if (topThresholds.size != NUM_PIE) {
- Log.wtf(TAG, "The number of topThresholds must be $NUM_PIE")
- return
- }
- setFloatUniform("in_topThresholds", topThresholds)
- }
-}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/modifier/BurnInModifiers.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/modifier/BurnInModifiers.kt
index 238a230..c109e51 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/modifier/BurnInModifiers.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/modifier/BurnInModifiers.kt
@@ -61,11 +61,10 @@
val scale =
when {
scaleViewModel.scaleClockOnly && isClock -> scaleViewModel.scale
- !scaleViewModel.scaleClockOnly -> scaleViewModel.scale
else -> 1f
}
- this.translationX = translationX
+ this.translationX = if (isClock) 0F else translationX
this.translationY = translationY
this.alpha = alpha
this.scaleX = scale
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/DefaultClockSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/DefaultClockSection.kt
index 7095875..09ec76d 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/DefaultClockSection.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/DefaultClockSection.kt
@@ -88,7 +88,7 @@
}
@Composable
- fun SceneScope.LargeClock(modifier: Modifier = Modifier) {
+ fun SceneScope.LargeClock(burnInParams: BurnInParameters, modifier: Modifier = Modifier) {
val currentClock by viewModel.currentClock.collectAsState()
if (currentClock?.largeClock?.view == null) {
return
@@ -129,7 +129,13 @@
update = {
it.ensureClockViewExists(checkNotNull(currentClock).largeClock.view)
},
- modifier = Modifier.fillMaxSize()
+ modifier =
+ Modifier.fillMaxSize()
+ .burnInAware(
+ viewModel = aodBurnInViewModel,
+ params = burnInParams,
+ isClock = true
+ )
)
}
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/TopAreaSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/TopAreaSection.kt
index 0934b20..e0540bf 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/TopAreaSection.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/TopAreaSection.kt
@@ -149,6 +149,7 @@
}
with(clockSection) {
LargeClock(
+ burnInParams = burnIn.parameters,
modifier =
Modifier.fillMaxSize().thenIf(shouldOffSetClockToOneHalf) {
// If we do not have a custom position animation, we want
@@ -179,7 +180,12 @@
Column(modifier = modifier) {
val currentClock = currentClockState.value ?: return@Column
- with(weatherClockSection) { Time(clock = currentClock, modifier = Modifier) }
+ with(weatherClockSection) {
+ Time(
+ clock = currentClock,
+ burnInParams = burnIn.parameters,
+ )
+ }
val density = LocalDensity.current
val context = LocalContext.current
@@ -193,7 +199,12 @@
)
)
}
- with(weatherClockSection) { LargeClockSectionBelowSmartspace(clock = currentClock) }
+ with(weatherClockSection) {
+ LargeClockSectionBelowSmartspace(
+ burnInParams = burnIn.parameters,
+ clock = currentClock,
+ )
+ }
}
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/WeatherClockSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/WeatherClockSection.kt
index a7bb308ad..9a82da2 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/WeatherClockSection.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/WeatherClockSection.kt
@@ -35,7 +35,9 @@
import com.android.compose.modifiers.padding
import com.android.systemui.customization.R as customizationR
import com.android.systemui.keyguard.ui.composable.blueprint.WeatherClockElementKeys
+import com.android.systemui.keyguard.ui.composable.modifier.burnInAware
import com.android.systemui.keyguard.ui.viewmodel.AodBurnInViewModel
+import com.android.systemui.keyguard.ui.viewmodel.BurnInParameters
import com.android.systemui.keyguard.ui.viewmodel.KeyguardClockViewModel
import com.android.systemui.plugins.clocks.ClockController
import javax.inject.Inject
@@ -50,19 +52,19 @@
@Composable
fun SceneScope.Time(
clock: ClockController,
- modifier: Modifier = Modifier,
+ burnInParams: BurnInParameters,
) {
Row(
modifier =
Modifier.padding(
- horizontal = dimensionResource(customizationR.dimen.clock_padding_start)
- )
+ horizontal = dimensionResource(customizationR.dimen.clock_padding_start)
+ )
+ .burnInAware(aodBurnInViewModel, burnInParams, isClock = true)
) {
WeatherElement(
weatherClockElementViewId = customizationR.id.weather_clock_time,
clock = clock,
elementKey = WeatherClockElementKeys.timeElementKey,
- modifier = modifier,
)
}
}
@@ -124,7 +126,7 @@
weatherClockElementViewId: Int,
clock: ClockController,
elementKey: ElementKey,
- modifier: Modifier
+ modifier: Modifier = Modifier,
) {
MovableElement(key = elementKey, modifier) {
content {
@@ -150,6 +152,7 @@
@Composable
fun SceneScope.LargeClockSectionBelowSmartspace(
+ burnInParams: BurnInParameters,
clock: ClockController,
) {
Row(
@@ -158,6 +161,7 @@
.padding(
horizontal = dimensionResource(customizationR.dimen.clock_padding_start)
)
+ .burnInAware(aodBurnInViewModel, burnInParams, isClock = true)
) {
Date(clock = clock, modifier = Modifier.wrapContentSize())
Box(
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt
index fc32440..f6575dc 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt
@@ -78,9 +78,9 @@
import com.android.systemui.shade.ui.composable.Shade
import com.android.systemui.shade.ui.composable.ShadeHeader
import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationsPlaceholderViewModel
-import com.android.systemui.statusbar.phone.StatusBarIconController
-import com.android.systemui.statusbar.phone.StatusBarIconController.TintedIconManager
import com.android.systemui.statusbar.phone.StatusBarLocation
+import com.android.systemui.statusbar.phone.ui.StatusBarIconController
+import com.android.systemui.statusbar.phone.ui.TintedIconManager
import javax.inject.Inject
import kotlin.math.roundToInt
import kotlinx.coroutines.CoroutineScope
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt
index 516e140..d3b3d15 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt
@@ -69,10 +69,10 @@
import com.android.systemui.shade.ui.composable.ShadeHeader.Dimensions.CollapsedHeight
import com.android.systemui.shade.ui.composable.ShadeHeader.Values.ClockScale
import com.android.systemui.shade.ui.viewmodel.ShadeHeaderViewModel
-import com.android.systemui.statusbar.phone.StatusBarIconController
-import com.android.systemui.statusbar.phone.StatusBarIconController.TintedIconManager
import com.android.systemui.statusbar.phone.StatusBarLocation
import com.android.systemui.statusbar.phone.StatusIconContainer
+import com.android.systemui.statusbar.phone.ui.StatusBarIconController
+import com.android.systemui.statusbar.phone.ui.TintedIconManager
import com.android.systemui.statusbar.pipeline.mobile.ui.view.ModernShadeCarrierGroupMobileView
import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.ShadeCarrierGroupMobileIconViewModel
import com.android.systemui.statusbar.policy.Clock
@@ -372,6 +372,20 @@
val batteryIcon = BatteryMeterView(context, null)
batteryIcon.setPercentShowMode(BatteryMeterView.MODE_ON)
+ val themedContext =
+ ContextThemeWrapper(context, R.style.Theme_SystemUI_QuickSettings_Header)
+ val fg = Utils.getColorAttrDefaultColor(themedContext, android.R.attr.textColorPrimary)
+ val bg =
+ Utils.getColorAttrDefaultColor(
+ themedContext,
+ android.R.attr.textColorPrimaryInverse,
+ )
+
+ // [BatteryMeterView.updateColors] is an old method that was built to distinguish
+ // between dual-tone colors and single-tone. The current icon is only single-tone, so
+ // the final [fg] is the only one we actually need
+ batteryIcon.updateColors(fg, bg, fg)
+
val batteryMaterViewController =
createBatteryMeterViewController(batteryIcon, StatusBarLocation.QS)
batteryMaterViewController.init()
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
index 944d6ef..91a9d2a 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
@@ -82,9 +82,9 @@
import com.android.systemui.scene.ui.composable.ComposableScene
import com.android.systemui.shade.shared.model.ShadeMode
import com.android.systemui.shade.ui.viewmodel.ShadeSceneViewModel
-import com.android.systemui.statusbar.phone.StatusBarIconController
-import com.android.systemui.statusbar.phone.StatusBarIconController.TintedIconManager
import com.android.systemui.statusbar.phone.StatusBarLocation
+import com.android.systemui.statusbar.phone.ui.StatusBarIconController
+import com.android.systemui.statusbar.phone.ui.TintedIconManager
import com.android.systemui.util.animation.MeasurementInput
import javax.inject.Inject
import javax.inject.Named
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateToScene.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateToScene.kt
index da07f6d..6b289f3 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateToScene.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateToScene.kt
@@ -190,4 +190,4 @@
// TODO(b/290184746): Compute a good default visibility threshold that depends on the layout size
// and screen density.
-private const val ProgressVisibilityThreshold = 1e-3f
+internal const val ProgressVisibilityThreshold = 1e-3f
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt
index 32cebd1..a595c66 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt
@@ -682,6 +682,17 @@
}
if (isBouncing) {
bouncingScene = targetScene
+
+ // Immediately stop this transition if we are bouncing on a
+ // scene that does not bounce.
+ val overscrollSpec = currentOverscrollSpec
+ if (
+ overscrollSpec != null &&
+ overscrollSpec.transformationSpec.transformations
+ .isEmpty()
+ ) {
+ snapToScene(targetScene)
+ }
}
}
}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt
index 7d43ca8..4273b4f 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt
@@ -24,6 +24,7 @@
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.geometry.isSpecified
import androidx.compose.ui.geometry.isUnspecified
import androidx.compose.ui.geometry.lerp
import androidx.compose.ui.graphics.CompositingStrategy
@@ -55,9 +56,15 @@
internal class Element(val key: ElementKey) {
/** The mapping between a scene and the state this element has in that scene, if any. */
// TODO(b/316901148): Make this a normal map instead once we can make sure that new transitions
- // are first seen by composition then layout/drawing code. See 316901148#comment2 for details.
+ // are first seen by composition then layout/drawing code. See b/316901148#comment2 for details.
val sceneStates = SnapshotStateMap<SceneKey, SceneState>()
+ /**
+ * The last transition that was used when computing the state (size, position and alpha) of this
+ * element in any scene, or `null` if it was last laid out when idle.
+ */
+ var lastTransition: TransitionState.Transition? = null
+
override fun toString(): String {
return "Element(key=$key)"
}
@@ -65,9 +72,33 @@
/** The last and target state of this element in a given scene. */
@Stable
class SceneState(val scene: SceneKey) {
+ /**
+ * The *target* state of this element in this scene, i.e. the state of this element when we
+ * are idle on this scene.
+ */
var targetSize by mutableStateOf(SizeUnspecified)
var targetOffset by mutableStateOf(Offset.Unspecified)
+ /** The last state this element had in this scene. */
+ var lastOffset = Offset.Unspecified
+ var lastScale = Scale.Unspecified
+ var lastAlpha = AlphaUnspecified
+
+ /** The state of this element in this scene right before the last interruption (if any). */
+ var offsetBeforeInterruption = Offset.Unspecified
+ var scaleBeforeInterruption = Scale.Unspecified
+ var alphaBeforeInterruption = AlphaUnspecified
+
+ /**
+ * The delta values to add to this element state to have smoother interruptions. These
+ * should be multiplied by the
+ * [current interruption progress][TransitionState.Transition.interruptionProgress] so that
+ * they nicely animate from their values down to 0.
+ */
+ var offsetInterruptionDelta = Offset.Zero
+ var scaleInterruptionDelta = Scale.Zero
+ var alphaInterruptionDelta = 0f
+
/**
* The attached [ElementNode] a Modifier.element() for a given element and scene. During
* composition, this set could have 0 to 2 elements. After composition and after all
@@ -78,12 +109,15 @@
companion object {
val SizeUnspecified = IntSize(Int.MAX_VALUE, Int.MAX_VALUE)
+ val AlphaUnspecified = Float.MAX_VALUE
}
}
data class Scale(val scaleX: Float, val scaleY: Float, val pivot: Offset = Offset.Unspecified) {
companion object {
val Default = Scale(1f, 1f, Offset.Unspecified)
+ val Zero = Scale(0f, 0f, Offset.Zero)
+ val Unspecified = Scale(Float.MAX_VALUE, Float.MAX_VALUE, Offset.Unspecified)
}
}
@@ -212,6 +246,10 @@
val isOtherSceneOverscrolling = overscrollScene != null && overscrollScene != scene.key
val isNotPartOfAnyOngoingTransitions = transitions.isNotEmpty() && transition == null
if (isNotPartOfAnyOngoingTransitions || isOtherSceneOverscrolling) {
+ sceneState.lastOffset = Offset.Unspecified
+ sceneState.lastScale = Scale.Unspecified
+ sceneState.lastAlpha = Element.AlphaUnspecified
+
val placeable = measurable.measure(constraints)
return layout(placeable.width, placeable.height) {}
}
@@ -233,7 +271,7 @@
override fun ContentDrawScope.draw() {
val transition = elementTransition(element, layoutImpl.state.currentTransitions)
- val drawScale = getDrawScale(layoutImpl, scene, element, transition)
+ val drawScale = getDrawScale(layoutImpl, scene, element, transition, sceneState)
if (drawScale == Scale.Default) {
drawContent()
} else {
@@ -276,8 +314,116 @@
element: Element,
transitions: List<TransitionState.Transition>,
): TransitionState.Transition? {
- return transitions.fastLastOrNull { transition ->
- transition.fromScene in element.sceneStates || transition.toScene in element.sceneStates
+ val transition =
+ transitions.fastLastOrNull { transition ->
+ transition.fromScene in element.sceneStates || transition.toScene in element.sceneStates
+ }
+
+ val previousTransition = element.lastTransition
+ element.lastTransition = transition
+
+ if (transition != previousTransition && transition != null && previousTransition != null) {
+ // The previous transition was interrupted by another transition.
+ prepareInterruption(element)
+ }
+
+ if (transition == null && previousTransition != null) {
+ // The transition was just finished.
+ element.sceneStates.values.forEach { sceneState ->
+ sceneState.offsetInterruptionDelta = Offset.Zero
+ sceneState.scaleInterruptionDelta = Scale.Zero
+ sceneState.alphaInterruptionDelta = 0f
+ }
+ }
+
+ return transition
+}
+
+private fun prepareInterruption(element: Element) {
+ // We look for the last unique state of this element so that we animate the delta with its
+ // future state.
+ val sceneStates = element.sceneStates.values
+ var lastUniqueState: Element.SceneState? = null
+ for (sceneState in sceneStates) {
+ val offset = sceneState.lastOffset
+
+ // If the element was placed in this scene...
+ if (offset != Offset.Unspecified) {
+ // ... and it is the first (and potentially the only) scene where the element was
+ // placed, save the state for later.
+ if (lastUniqueState == null) {
+ lastUniqueState = sceneState
+ } else {
+ // The element was placed in multiple scenes: we abort the interruption for this
+ // element.
+ // TODO(b/290930950): Better support cases where a shared element animation is
+ // disabled and the same element is drawn/placed in multiple scenes at the same
+ // time.
+ lastUniqueState = null
+ break
+ }
+ }
+ }
+
+ val lastOffset = lastUniqueState?.lastOffset ?: Offset.Unspecified
+ val lastScale = lastUniqueState?.lastScale ?: Scale.Unspecified
+ val lastAlpha = lastUniqueState?.lastAlpha ?: Element.AlphaUnspecified
+
+ // Store the state of the element before the interruption and reset the deltas.
+ sceneStates.forEach { sceneState ->
+ sceneState.offsetBeforeInterruption = lastOffset
+ sceneState.scaleBeforeInterruption = lastScale
+ sceneState.alphaBeforeInterruption = lastAlpha
+
+ sceneState.offsetInterruptionDelta = Offset.Zero
+ sceneState.scaleInterruptionDelta = Scale.Zero
+ sceneState.alphaInterruptionDelta = 0f
+ }
+}
+
+/**
+ * Compute what [value] should be if we take the
+ * [interruption progress][TransitionState.Transition.interruptionProgress] of [transition] into
+ * account.
+ */
+private inline fun <T> computeInterruptedValue(
+ layoutImpl: SceneTransitionLayoutImpl,
+ transition: TransitionState.Transition?,
+ value: T,
+ unspecifiedValue: T,
+ zeroValue: T,
+ getValueBeforeInterruption: () -> T,
+ setValueBeforeInterruption: (T) -> Unit,
+ getInterruptionDelta: () -> T,
+ setInterruptionDelta: (T) -> Unit,
+ diff: (a: T, b: T) -> T, // a - b
+ add: (a: T, b: T, bProgress: Float) -> T, // a + (b * bProgress)
+): T {
+ val valueBeforeInterruption = getValueBeforeInterruption()
+
+ // If the value before the interruption is specified, it means that this is the first time we
+ // compute [value] right after an interruption.
+ if (valueBeforeInterruption != unspecifiedValue) {
+ // Compute and store the delta between the value before the interruption and the current
+ // value.
+ setInterruptionDelta(diff(valueBeforeInterruption, value))
+
+ // Reset the value before interruption now that we processed it.
+ setValueBeforeInterruption(unspecifiedValue)
+ }
+
+ val delta = getInterruptionDelta()
+ return if (delta == zeroValue || transition == null) {
+ // There was no interruption or there is no transition: just return the value.
+ value
+ } else {
+ // Add `delta * interruptionProgress` to the value so that we animate to value.
+ val interruptionProgress = transition.interruptionProgress(layoutImpl)
+ if (interruptionProgress == 0f) {
+ value
+ } else {
+ add(value, delta, interruptionProgress)
+ }
}
}
@@ -417,20 +563,47 @@
scene: Scene,
element: Element,
transition: TransitionState.Transition?,
+ sceneState: Element.SceneState,
): Float {
- return computeValue(
- layoutImpl,
- scene,
- element,
- transition,
- sceneValue = { 1f },
- transformation = { it.alpha },
- idleValue = 1f,
- currentValue = { 1f },
- isSpecified = { true },
- ::lerp,
- )
- .fastCoerceIn(0f, 1f)
+ val alpha =
+ computeValue(
+ layoutImpl,
+ scene,
+ element,
+ transition,
+ sceneValue = { 1f },
+ transformation = { it.alpha },
+ idleValue = 1f,
+ currentValue = { 1f },
+ isSpecified = { true },
+ ::lerp,
+ )
+ .fastCoerceIn(0f, 1f)
+
+ val interruptedAlpha = interruptedAlpha(layoutImpl, transition, sceneState, alpha)
+ sceneState.lastAlpha = interruptedAlpha
+ return interruptedAlpha
+}
+
+private fun interruptedAlpha(
+ layoutImpl: SceneTransitionLayoutImpl,
+ transition: TransitionState.Transition?,
+ sceneState: Element.SceneState,
+ alpha: Float,
+): Float {
+ return computeInterruptedValue(
+ layoutImpl,
+ transition,
+ value = alpha,
+ unspecifiedValue = Element.AlphaUnspecified,
+ zeroValue = 0f,
+ getValueBeforeInterruption = { sceneState.alphaBeforeInterruption },
+ setValueBeforeInterruption = { sceneState.alphaBeforeInterruption = it },
+ getInterruptionDelta = { sceneState.alphaInterruptionDelta },
+ setInterruptionDelta = { sceneState.alphaInterruptionDelta = it },
+ diff = { a, b -> a - b },
+ add = { a, b, bProgress -> a + b * bProgress },
+ )
}
@OptIn(ExperimentalComposeUiApi::class)
@@ -480,24 +653,70 @@
)
}
-private fun getDrawScale(
+private fun ContentDrawScope.getDrawScale(
layoutImpl: SceneTransitionLayoutImpl,
scene: Scene,
element: Element,
transition: TransitionState.Transition?,
+ sceneState: Element.SceneState,
): Scale {
- return computeValue(
- layoutImpl,
- scene,
- element,
- transition,
- sceneValue = { Scale.Default },
- transformation = { it.drawScale },
- idleValue = Scale.Default,
- currentValue = { Scale.Default },
- isSpecified = { true },
- ::lerp,
- )
+ val scale =
+ computeValue(
+ layoutImpl,
+ scene,
+ element,
+ transition,
+ sceneValue = { Scale.Default },
+ transformation = { it.drawScale },
+ idleValue = Scale.Default,
+ currentValue = { Scale.Default },
+ isSpecified = { true },
+ ::lerp,
+ )
+
+ fun Offset.specifiedOrCenter(): Offset {
+ return this.takeIf { isSpecified } ?: center
+ }
+
+ val interruptedScale =
+ computeInterruptedValue(
+ layoutImpl,
+ transition,
+ value = scale,
+ unspecifiedValue = Scale.Unspecified,
+ zeroValue = Scale.Zero,
+ getValueBeforeInterruption = { sceneState.scaleBeforeInterruption },
+ setValueBeforeInterruption = { sceneState.scaleBeforeInterruption = it },
+ getInterruptionDelta = { sceneState.scaleInterruptionDelta },
+ setInterruptionDelta = { sceneState.scaleInterruptionDelta = it },
+ diff = { a, b ->
+ Scale(
+ scaleX = a.scaleX - b.scaleX,
+ scaleY = a.scaleY - b.scaleY,
+ pivot =
+ if (a.pivot.isUnspecified && b.pivot.isUnspecified) {
+ Offset.Unspecified
+ } else {
+ a.pivot.specifiedOrCenter() - b.pivot.specifiedOrCenter()
+ }
+ )
+ },
+ add = { a, b, bProgress ->
+ Scale(
+ scaleX = a.scaleX + b.scaleX * bProgress,
+ scaleY = a.scaleY + b.scaleY * bProgress,
+ pivot =
+ if (a.pivot.isUnspecified && b.pivot.isUnspecified) {
+ Offset.Unspecified
+ } else {
+ a.pivot.specifiedOrCenter() + b.pivot.specifiedOrCenter() * bProgress
+ }
+ )
+ }
+ )
+
+ sceneState.lastScale = interruptedScale
+ return interruptedScale
}
@OptIn(ExperimentalComposeUiApi::class)
@@ -524,6 +743,8 @@
// No need to place the element in this scene if we don't want to draw it anyways.
if (!shouldPlaceElement(layoutImpl, scene, element, transition)) {
+ sceneState.lastOffset = Offset.Unspecified
+ sceneState.offsetBeforeInterruption = Offset.Unspecified
return
}
@@ -542,15 +763,37 @@
::lerp,
)
- val offset = (targetOffset - currentOffset).round()
- if (isElementOpaque(scene, element, transition)) {
+ val interruptedOffset =
+ computeInterruptedValue(
+ layoutImpl,
+ transition,
+ value = targetOffset,
+ unspecifiedValue = Offset.Unspecified,
+ zeroValue = Offset.Zero,
+ getValueBeforeInterruption = { sceneState.offsetBeforeInterruption },
+ setValueBeforeInterruption = { sceneState.offsetBeforeInterruption = it },
+ getInterruptionDelta = { sceneState.offsetInterruptionDelta },
+ setInterruptionDelta = { sceneState.offsetInterruptionDelta = it },
+ diff = { a, b -> a - b },
+ add = { a, b, bProgress -> a + b * bProgress },
+ )
+
+ sceneState.lastOffset = interruptedOffset
+
+ val offset = (interruptedOffset - currentOffset).round()
+ if (
+ isElementOpaque(scene, element, transition) &&
+ interruptedAlpha(layoutImpl, transition, sceneState, alpha = 1f) == 1f
+ ) {
+ sceneState.lastAlpha = 1f
+
// TODO(b/291071158): Call placeWithLayer() if offset != IntOffset.Zero and size is not
// animated once b/305195729 is fixed. Test that drawing is not invalidated in that
// case.
placeable.place(offset)
} else {
placeable.placeWithLayer(offset) {
- alpha = elementAlpha(layoutImpl, scene, element, transition)
+ alpha = elementAlpha(layoutImpl, scene, element, transition, sceneState)
compositingStrategy = CompositingStrategy.ModulateAlpha
}
}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt
index 20dcc20..ad691ba 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt
@@ -49,7 +49,7 @@
internal var swipeSourceDetector: SwipeSourceDetector,
internal var transitionInterceptionThreshold: Float,
builder: SceneTransitionLayoutScope.() -> Unit,
- private val coroutineScope: CoroutineScope,
+ internal val coroutineScope: CoroutineScope,
) {
/**
* The map of [Scene]s.
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
index f13c016..5fda77a 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
@@ -18,6 +18,9 @@
import android.util.Log
import androidx.annotation.VisibleForTesting
+import androidx.compose.animation.core.Animatable
+import androidx.compose.animation.core.AnimationVector1D
+import androidx.compose.animation.core.spring
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
@@ -34,6 +37,7 @@
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.channels.Channel
+import kotlinx.coroutines.launch
/**
* The state of a [SceneTransitionLayout].
@@ -253,6 +257,12 @@
}
}
+ /**
+ * An animatable that animates from 1f to 0f. This will be used to nicely animate the sudden
+ * jump of values when this transitions interrupts another one.
+ */
+ private var interruptionDecay: Animatable<Float, AnimationVector1D>? = null
+
init {
check(fromScene != toScene)
}
@@ -289,6 +299,33 @@
fromOverscrollSpec = fromSpec
toOverscrollSpec = toSpec
}
+
+ internal open fun interruptionProgress(
+ layoutImpl: SceneTransitionLayoutImpl,
+ ): Float {
+ if (!layoutImpl.state.enableInterruptions) {
+ return 0f
+ }
+
+ fun create(): Animatable<Float, AnimationVector1D> {
+ val animatable = Animatable(1f, visibilityThreshold = ProgressVisibilityThreshold)
+ layoutImpl.coroutineScope.launch {
+ val swipeSpec = layoutImpl.state.transitions.defaultSwipeSpec
+ val progressSpec =
+ spring(
+ stiffness = swipeSpec.stiffness,
+ dampingRatio = swipeSpec.dampingRatio,
+ visibilityThreshold = ProgressVisibilityThreshold,
+ )
+ animatable.animateTo(0f, progressSpec)
+ }
+
+ return animatable
+ }
+
+ val animatable = interruptionDecay ?: create().also { interruptionDecay = it }
+ return animatable.value
+ }
}
interface HasOverscrollProperties {
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt
index b7fc91c..b1d7055 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt
@@ -37,6 +37,7 @@
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.SideEffect
import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableFloatStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
@@ -55,7 +56,10 @@
import androidx.compose.ui.test.onRoot
import androidx.compose.ui.test.performTouchInput
import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.DpOffset
+import androidx.compose.ui.unit.DpSize
import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.lerp
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.compose.animation.scene.TestScenes.SceneA
import com.android.compose.animation.scene.TestScenes.SceneB
@@ -1019,4 +1023,122 @@
rule.onNode(isElement(TestElements.Foo)).assertDoesNotExist()
rule.onNode(isElement(TestElements.Bar)).assertPositionInRootIsEqualTo(100.dp, 100.dp)
}
+
+ @Test
+ fun interruption() = runTest {
+ // 4 frames of animation.
+ val duration = 4 * 16
+
+ val state =
+ MutableSceneTransitionLayoutStateImpl(
+ SceneA,
+ transitions {
+ from(SceneA, to = SceneB) { spec = tween(duration, easing = LinearEasing) }
+ from(SceneB, to = SceneC) { spec = tween(duration, easing = LinearEasing) }
+ },
+ enableInterruptions = false,
+ )
+
+ val layoutSize = DpSize(200.dp, 100.dp)
+ val fooSize = DpSize(20.dp, 10.dp)
+
+ @Composable
+ fun SceneScope.Foo(modifier: Modifier = Modifier) {
+ Box(modifier.element(TestElements.Foo).size(fooSize))
+ }
+
+ rule.setContent {
+ SceneTransitionLayout(state, Modifier.size(layoutSize)) {
+ // In scene A, Foo is aligned at the TopStart.
+ scene(SceneA) {
+ Box(Modifier.fillMaxSize()) { Foo(Modifier.align(Alignment.TopStart)) }
+ }
+
+ // In scene B, Foo is aligned at the TopEnd, so it moves horizontally when coming
+ // from A.
+ scene(SceneB) {
+ Box(Modifier.fillMaxSize()) { Foo(Modifier.align(Alignment.TopEnd)) }
+ }
+
+ // In scene C, Foo is aligned at the BottomEnd, so it moves vertically when coming
+ // from B.
+ scene(SceneC) {
+ Box(Modifier.fillMaxSize()) { Foo(Modifier.align(Alignment.BottomEnd)) }
+ }
+ }
+ }
+
+ // The offset of Foo when idle in A, B or C.
+ val offsetInA = DpOffset.Zero
+ val offsetInB = DpOffset(layoutSize.width - fooSize.width, 0.dp)
+ val offsetInC =
+ DpOffset(layoutSize.width - fooSize.width, layoutSize.height - fooSize.height)
+
+ // Initial state (idle in A).
+ rule
+ .onNode(isElement(TestElements.Foo, SceneA))
+ .assertPositionInRootIsEqualTo(offsetInA.x, offsetInA.y)
+
+ // Current transition is A => B at 50%.
+ val aToBProgress = 0.5f
+ val aToB =
+ transition(
+ from = SceneA,
+ to = SceneB,
+ progress = { aToBProgress },
+ onFinish = neverFinish(),
+ )
+ val offsetInAToB = lerp(offsetInA, offsetInB, aToBProgress)
+ rule.runOnUiThread { state.startTransition(aToB, transitionKey = null) }
+ rule
+ .onNode(isElement(TestElements.Foo, SceneB))
+ .assertPositionInRootIsEqualTo(offsetInAToB.x, offsetInAToB.y)
+
+ // Start B => C at 0%.
+ var bToCProgress by mutableFloatStateOf(0f)
+ var interruptionProgress by mutableFloatStateOf(1f)
+ val bToC =
+ transition(
+ from = SceneB,
+ to = SceneC,
+ progress = { bToCProgress },
+ interruptionProgress = { interruptionProgress },
+ )
+ rule.runOnUiThread { state.startTransition(bToC, transitionKey = null) }
+
+ // The offset interruption delta, which will be multiplied by the interruption progress then
+ // added to the current transition offset.
+ val interruptionDelta = offsetInAToB - offsetInB
+
+ // Interruption progress is at 100% and bToC is at 0%, so Foo should be at the same offset
+ // as right before the interruption.
+ rule
+ .onNode(isElement(TestElements.Foo, SceneC))
+ .assertPositionInRootIsEqualTo(offsetInAToB.x, offsetInAToB.y)
+
+ // Move the transition forward at 30% and set the interruption progress to 50%.
+ bToCProgress = 0.3f
+ interruptionProgress = 0.5f
+ val offsetInBToC = lerp(offsetInB, offsetInC, bToCProgress)
+ val offsetInBToCWithInterruption =
+ offsetInBToC +
+ DpOffset(
+ interruptionDelta.x * interruptionProgress,
+ interruptionDelta.y * interruptionProgress,
+ )
+ rule.waitForIdle()
+ rule
+ .onNode(isElement(TestElements.Foo, SceneC))
+ .assertPositionInRootIsEqualTo(
+ offsetInBToCWithInterruption.x,
+ offsetInBToCWithInterruption.y,
+ )
+
+ // Finish the transition and interruption.
+ bToCProgress = 1f
+ interruptionProgress = 0f
+ rule
+ .onNode(isElement(TestElements.Foo, SceneC))
+ .assertPositionInRootIsEqualTo(offsetInC.x, offsetInC.y)
+ }
}
diff --git a/packages/SystemUI/compose/scene/tests/utils/src/com/android/compose/animation/scene/Transition.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/Transition.kt
similarity index 73%
rename from packages/SystemUI/compose/scene/tests/utils/src/com/android/compose/animation/scene/Transition.kt
rename to packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/Transition.kt
index 767057b..c1218ae 100644
--- a/packages/SystemUI/compose/scene/tests/utils/src/com/android/compose/animation/scene/Transition.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/Transition.kt
@@ -18,12 +18,17 @@
import androidx.compose.foundation.gestures.Orientation
import kotlinx.coroutines.Job
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.sync.Mutex
+import kotlinx.coroutines.sync.withLock
+import kotlinx.coroutines.test.TestScope
/** A utility to easily create a [TransitionState.Transition] in tests. */
fun transition(
from: SceneKey,
to: SceneKey,
progress: () -> Float = { 0f },
+ interruptionProgress: () -> Float = { 100f },
isInitiatedByUserInput: Boolean = false,
isUserInputOngoing: Boolean = false,
isUpOrLeft: Boolean = false,
@@ -55,5 +60,22 @@
return onFinish(this)
}
+
+ override fun interruptionProgress(layoutImpl: SceneTransitionLayoutImpl): Float {
+ return interruptionProgress()
+ }
+ }
+}
+
+/**
+ * Return a onFinish lambda that can be used with [transition] so that the transition never
+ * finishes. This allows to keep the transition in the current transitions list.
+ */
+fun TestScope.neverFinish(): (TransitionState.Transition) -> Job {
+ return {
+ backgroundScope.launch {
+ // Try to acquire a locked mutex so that this code never completes.
+ Mutex(locked = true).withLock {}
+ }
}
}
diff --git a/packages/SystemUI/docs/scene.md b/packages/SystemUI/docs/scene.md
index f331c9b..fb8a271 100644
--- a/packages/SystemUI/docs/scene.md
+++ b/packages/SystemUI/docs/scene.md
@@ -65,23 +65,25 @@
[`SceneContainerFlags.kt`](https://cs.android.com/android/platform/superproject/main/+/main:frameworks/base/packages/SystemUI/src/com/android/systemui/scene/shared/flag/SceneContainerFlags.kt)
file evalutes to `true`.
-1. Set the **`migrate_keyguard_status_bar_view`** classic flag to `true` by
- running: `console $ adb shell statusbar cmd migrate_keyguard_status_bar_view
- true`
-2. Set a collection of **aconfig flags** to `true` by running the following
+1. Set a collection of **aconfig flags** to `true` by running the following
commands:
```console
- $ adb shell device_config put systemui com.android.systemui.scene_container true
- $ adb shell device_config put systemui com.android.systemui.compose_lockscreen true
- $ adb shell device_config put systemui com.android.systemui.keyguard_bottom_area_refactor true
- $ adb shell device_config put systemui com.android.systemui.media_in_scene_container true
- $ adb shell device_config put systemui com.android.systemui.migrate_clocks_to_blueprint true
+ $ adb shell device_config override systemui com.android.systemui.scene_container true
+ $ adb shell device_config override systemui com.android.systemui.compose_lockscreen true
+ $ adb shell device_config override systemui com.android.systemui.keyguard_bottom_area_refactor true
+ $ adb shell device_config override systemui com.android.systemui.keyguard_wm_state_refactor true
+ $ adb shell device_config override systemui com.android.systemui.media_in_scene_container true
+ $ adb shell device_config override systemui com.android.systemui.migrate_clocks_to_blueprint true
+ $ adb shell device_config override systemui com.android.systemui.notification_heads_up_refactor true
+ $ adb shell device_config override systemui com.android.systemui.predictive_back_sysui true
+ $ adb shell device_config override systemui com.android.systemui.device_entry_udfps_refactor true
+ $ adb shell device_config override systemui com.android.systemui.refactor_keyguard_dismiss_intent true
```
-3. **Restart** System UI by issuing the following command:
+2. **Restart** System UI by issuing the following command:
```console
$ adb shell am crash com.android.systemui
```
-4. **Verify** that the scene framework was turned on. There are two ways to do
+3. **Verify** that the scene framework was turned on. There are two ways to do
this:
*(a)* look for the sash/ribbon UI at the bottom-right corner of the display:
diff --git a/packages/SystemUI/monet/src/com/android/systemui/monet/Shades.java b/packages/SystemUI/monet/src/com/android/systemui/monet/Shades.java
index c97b960..c8b9fe0 100644
--- a/packages/SystemUI/monet/src/com/android/systemui/monet/Shades.java
+++ b/packages/SystemUI/monet/src/com/android/systemui/monet/Shades.java
@@ -21,7 +21,6 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.graphics.ColorUtils;
-
/**
* Generate sets of colors that are shades of the same color
*/
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/ambient/touch/BouncerSwipeTouchHandlerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/ambient/touch/BouncerSwipeTouchHandlerTest.java
index fefe5a0..3395268 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/ambient/touch/BouncerSwipeTouchHandlerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/ambient/touch/BouncerSwipeTouchHandlerTest.java
@@ -66,6 +66,7 @@
import java.util.Collections;
import java.util.Optional;
+
@SmallTest
@RunWith(AndroidJUnit4.class)
public class BouncerSwipeTouchHandlerTest extends SysuiTestCase {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
index 9b0b5de..f3de463e 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -118,6 +118,8 @@
import dagger.Lazy;
+import kotlinx.coroutines.CoroutineScope;
+
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -132,8 +134,6 @@
import java.util.ArrayList;
import java.util.List;
-import kotlinx.coroutines.CoroutineScope;
-
@SmallTest
@RunWith(AndroidJUnit4.class)
@RunWithLooper(setAsMainLooper = true)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelTest.kt
index b83c0ce..ecfcc90 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelTest.kt
@@ -38,6 +38,7 @@
import com.android.systemui.flags.Flags
import com.android.systemui.flags.fakeFeatureFlagsClassic
import com.android.systemui.kosmos.testScope
+import com.android.systemui.scene.domain.interactor.sceneContainerStartable
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.scene.shared.model.fakeSceneDataSource
import com.android.systemui.testKosmos
@@ -67,10 +68,13 @@
private val testScope = kosmos.testScope
private val authenticationInteractor by lazy { kosmos.authenticationInteractor }
private val bouncerInteractor by lazy { kosmos.bouncerInteractor }
+ private val sceneContainerStartable = kosmos.sceneContainerStartable
+
private lateinit var underTest: BouncerViewModel
@Before
fun setUp() {
+ sceneContainerStartable.start()
underTest = kosmos.bouncerViewModel
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/data/repository/DeviceEntryFaceAuthRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/data/repository/DeviceEntryFaceAuthRepositoryTest.kt
index 6b2a1d5..e9dc261 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/data/repository/DeviceEntryFaceAuthRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/data/repository/DeviceEntryFaceAuthRepositoryTest.kt
@@ -654,7 +654,7 @@
}
@Test
- fun authenticateFallbacksToDetectionWhenUserIsAlreadyTrustedByTrustManager() =
+ fun authenticateFallbacksToDetectionWhenKeyguardIsAlreadyDismissible() =
testScope.runTest {
whenever(faceManager.sensorPropertiesInternal)
.thenReturn(listOf(createFaceSensorProperties(supportsFaceDetection = true)))
@@ -663,7 +663,7 @@
initCollectors()
allPreconditionsToRunFaceAuthAreTrue()
- trustRepository.setCurrentUserTrusted(true)
+ keyguardRepository.setKeyguardDismissible(true)
assertThat(canFaceAuthRun()).isFalse()
underTest.requestAuthenticate(
FACE_AUTH_TRIGGERED_SWIPE_UP_ON_BOUNCER,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java
index e2e5169..2b3f40f 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java
@@ -49,6 +49,8 @@
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
import com.android.systemui.statusbar.BlurUtils;
+import kotlinx.coroutines.CoroutineDispatcher;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -56,8 +58,6 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import kotlinx.coroutines.CoroutineDispatcher;
-
@SmallTest
@RunWith(AndroidJUnit4.class)
@RunWithLooper(setAsMainLooper = true)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayServiceTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayServiceTest.kt
index bdb0c9a..11f9e1c 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayServiceTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayServiceTest.kt
@@ -689,6 +689,31 @@
)
}
+ // Verifies that the touch handling lifecycle is STARTED even if the dream starts while not
+ // focused.
+ @Test
+ fun testLifecycle_dreamNotFocusedOnStart_isStarted() {
+ val transitionState: MutableStateFlow<ObservableTransitionState> =
+ MutableStateFlow(ObservableTransitionState.Idle(CommunalScenes.Blank))
+ communalRepository.setTransitionState(transitionState)
+
+ // Communal becomes visible.
+ transitionState.value = ObservableTransitionState.Idle(CommunalScenes.Communal)
+ testScope.runCurrent()
+ mMainExecutor.runAllReady()
+
+ // Start dreaming.
+ val client = client
+ client.startDream(
+ mWindowParams,
+ mDreamOverlayCallback,
+ DREAM_COMPONENT,
+ false /*shouldShowComplication*/
+ )
+ mMainExecutor.runAllReady()
+ assertThat(lifecycleRegistry.currentState).isEqualTo(Lifecycle.State.STARTED)
+ }
+
@Test
fun testLifecycle_destroyedAfterOnDestroy() {
val client = client
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/conditions/AssistantAttentionConditionTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/conditions/AssistantAttentionConditionTest.java
index cb5702ad..ccadd14 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/conditions/AssistantAttentionConditionTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/conditions/AssistantAttentionConditionTest.java
@@ -31,6 +31,8 @@
import com.android.systemui.assist.AssistManager.VisualQueryAttentionListener;
import com.android.systemui.shared.condition.Condition;
+import kotlinx.coroutines.CoroutineScope;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -38,8 +40,6 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import kotlinx.coroutines.CoroutineScope;
-
@SmallTest
@RunWith(AndroidJUnit4.class)
@android.platform.test.annotations.EnabledOnRavenwood
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/conditions/DreamConditionTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/conditions/DreamConditionTest.java
index 96d3c93..58c17e2 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/conditions/DreamConditionTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/conditions/DreamConditionTest.java
@@ -34,6 +34,8 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.shared.condition.Condition;
+import kotlinx.coroutines.CoroutineScope;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -41,8 +43,6 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import kotlinx.coroutines.CoroutineScope;
-
@SmallTest
@RunWith(AndroidJUnit4.class)
@android.platform.test.annotations.EnabledOnRavenwood
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/haptics/qs/QSLongPressEffectTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/haptics/qs/QSLongPressEffectTest.kt
index e332656..c51413a 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/haptics/qs/QSLongPressEffectTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/haptics/qs/QSLongPressEffectTest.kt
@@ -21,7 +21,6 @@
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
-import com.android.systemui.animation.AnimatorTestRule
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.haptics.vibratorHelper
import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
@@ -32,19 +31,14 @@
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runTest
import org.junit.Before
-import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
-import org.mockito.junit.MockitoJUnit
-import org.mockito.junit.MockitoRule
@SmallTest
@RunWith(AndroidJUnit4::class)
@RunWithLooper(setAsMainLooper = true)
class QSLongPressEffectTest : SysuiTestCase() {
- @Rule @JvmField val mMockitoRule: MockitoRule = MockitoJUnit.rule()
- @get:Rule val animatorTestRule = AnimatorTestRule(this)
private val kosmos = testKosmos()
private val vibratorHelper = kosmos.vibratorHelper
@@ -67,58 +61,28 @@
vibratorHelper,
kosmos.keyguardInteractor,
)
- longPressEffect.initializeEffect(effectDuration)
}
@Test
- fun onReset_whileIdle_resetsEffect() = testWithScope {
- // GIVEN a call to reset
- longPressEffect.resetEffect()
+ fun onInitialize_withNegativeDuration_doesNotInitialize() =
+ testWithScope(false) {
+ // WHEN attempting to initialize with a negative duration
+ val couldInitialize = longPressEffect.initializeEffect(-1)
- // THEN the effect remains idle and has not been initialized
- val state by collectLastValue(longPressEffect.state)
- assertThat(state).isEqualTo(QSLongPressEffect.State.IDLE)
- assertThat(longPressEffect.hasInitialized).isFalse()
- }
-
- @Test
- fun onReset_whileRunning_resetsEffect() = testWhileRunning {
- // GIVEN a call to reset
- longPressEffect.resetEffect()
-
- // THEN the effect remains idle and has not been initialized
- val state by collectLastValue(longPressEffect.state)
- assertThat(state).isEqualTo(QSLongPressEffect.State.IDLE)
- assertThat(longPressEffect.hasInitialized).isFalse()
- }
-
- @Test
- fun onInitialize_withNegativeDuration_doesNotInitialize() = testWithScope {
- // GIVEN an effect that has reset
- longPressEffect.resetEffect()
-
- // WHEN attempting to initialize with a negative duration
- val couldInitialize = longPressEffect.initializeEffect(-1)
-
- // THEN the effect can't initialized and remains reset
- val state by collectLastValue(longPressEffect.state)
- assertThat(couldInitialize).isFalse()
- assertThat(state).isEqualTo(QSLongPressEffect.State.IDLE)
- assertThat(longPressEffect.hasInitialized).isFalse()
- }
+ // THEN the effect can't initialized and remains reset
+ assertThat(couldInitialize).isFalse()
+ assertThat(longPressEffect.state).isEqualTo(QSLongPressEffect.State.IDLE)
+ assertThat(longPressEffect.hasInitialized).isFalse()
+ }
@Test
fun onInitialize_withPositiveDuration_initializes() = testWithScope {
- // GIVEN an effect that has reset
- longPressEffect.resetEffect()
-
// WHEN attempting to initialize with a positive duration
val couldInitialize = longPressEffect.initializeEffect(effectDuration)
// THEN the effect is initialized
- val state by collectLastValue(longPressEffect.state)
assertThat(couldInitialize).isTrue()
- assertThat(state).isEqualTo(QSLongPressEffect.State.IDLE)
+ assertThat(longPressEffect.state).isEqualTo(QSLongPressEffect.State.IDLE)
assertThat(longPressEffect.hasInitialized).isTrue()
}
@@ -128,140 +92,174 @@
longPressEffect.handleActionDown()
// THEN the effect moves to the TIMEOUT_WAIT state
- val state by collectLastValue(longPressEffect.state)
- assertThat(state).isEqualTo(QSLongPressEffect.State.TIMEOUT_WAIT)
+ assertThat(longPressEffect.state).isEqualTo(QSLongPressEffect.State.TIMEOUT_WAIT)
}
@Test
- fun onActionCancel_whileWaiting_goesIdle() = testWhileWaiting {
- // GIVEN an action cancel occurs
- longPressEffect.handleActionCancel()
+ fun onActionCancel_whileWaiting_goesIdle() =
+ testWhileInState(QSLongPressEffect.State.TIMEOUT_WAIT) {
+ // GIVEN an action cancel occurs
+ longPressEffect.handleActionCancel()
- // THEN the effect goes back to idle and does not start
- val state by collectLastValue(longPressEffect.state)
- assertThat(state).isEqualTo(QSLongPressEffect.State.IDLE)
- assertEffectDidNotStart()
+ // THEN the effect goes back to idle and does not start
+ assertThat(longPressEffect.state).isEqualTo(QSLongPressEffect.State.IDLE)
+ assertEffectDidNotStart()
+ }
+
+ @Test
+ fun onActionUp_whileWaiting_performsClick() =
+ testWhileInState(QSLongPressEffect.State.TIMEOUT_WAIT) {
+ // GIVEN an action is being collected
+ val action by collectLastValue(longPressEffect.actionType)
+
+ // GIVEN an action up occurs
+ longPressEffect.handleActionUp()
+
+ // THEN the action to invoke is the click action and the effect does not start
+ assertThat(action).isEqualTo(QSLongPressEffect.ActionType.CLICK)
+ assertEffectDidNotStart()
+ }
+
+ @Test
+ fun onWaitComplete_whileWaiting_beginsEffect() =
+ testWhileInState(QSLongPressEffect.State.TIMEOUT_WAIT) {
+ // GIVEN the pressed timeout is complete
+ longPressEffect.handleTimeoutComplete()
+
+ // THEN the effect emits the action to start an animator
+ val action by collectLastValue(longPressEffect.actionType)
+ assertThat(action).isEqualTo(QSLongPressEffect.ActionType.START_ANIMATOR)
+ }
+
+ @Test
+ fun onAnimationStart_whileWaiting_effectBegins() =
+ testWhileInState(QSLongPressEffect.State.TIMEOUT_WAIT) {
+ // GIVEN that the animator starts
+ longPressEffect.handleAnimationStart()
+
+ // THEN the effect begins
+ assertEffectStarted()
+ }
+
+ @Test
+ fun onActionUp_whileEffectHasBegun_reversesEffect() =
+ testWhileInState(QSLongPressEffect.State.RUNNING_FORWARD) {
+ // GIVEN an action up occurs
+ longPressEffect.handleActionUp()
+
+ // THEN the effect reverses
+ assertEffectReverses()
+ }
+
+ @Test
+ fun onPlayReverseHaptics_reverseHapticsArePlayed() = testWithScope {
+ // GIVEN a call to play reverse haptics at the effect midpoint
+ val progress = 0.5f
+ longPressEffect.playReverseHaptics(progress)
+
+ // THEN the expected texture is played
+ val reverseHaptics =
+ LongPressHapticBuilder.createReversedEffect(
+ progress,
+ lowTickDuration,
+ effectDuration,
+ )
+ assertThat(reverseHaptics).isNotNull()
+ assertThat(vibratorHelper.hasVibratedWithEffects(reverseHaptics!!)).isTrue()
}
@Test
- fun onActionUp_whileWaiting_performsClick() = testWhileWaiting {
- // GIVEN an action is being collected
- val action by collectLastValue(longPressEffect.actionType)
+ fun onActionCancel_whileEffectHasBegun_reversesEffect() =
+ testWhileInState(QSLongPressEffect.State.RUNNING_FORWARD) {
+ // WHEN an action cancel occurs
+ longPressEffect.handleActionCancel()
- // GIVEN an action up occurs
- longPressEffect.handleActionUp()
-
- // THEN the action to invoke is the click action and the effect does not start
- assertThat(action).isEqualTo(QSLongPressEffect.ActionType.CLICK)
- assertEffectDidNotStart()
- }
+ // THEN the effect gets reversed
+ assertEffectReverses()
+ }
@Test
- fun onWaitComplete_whileWaiting_beginsEffect() = testWhileWaiting {
- // GIVEN the pressed timeout is complete
- longPressEffect.handleTimeoutComplete()
+ fun onAnimationComplete_keyguardDismissible_effectEndsWithLongPress() =
+ testWhileInState(QSLongPressEffect.State.RUNNING_FORWARD) {
+ // GIVEN that the animation completes
+ longPressEffect.handleAnimationComplete()
- // THEN the effect starts
- assertEffectStarted()
- }
-
- @Test
- fun onActionUp_whileEffectHasBegun_reversesEffect() = testWhileRunning {
- // GIVEN that the effect is at the middle of its completion (progress of 50%)
- animatorTestRule.advanceTimeBy(effectDuration / 2L)
-
- // WHEN an action up occurs
- longPressEffect.handleActionUp()
-
- // THEN the effect gets reversed at 50% progress
- assertEffectReverses(0.5f)
- }
-
- @Test
- fun onActionCancel_whileEffectHasBegun_reversesEffect() = testWhileRunning {
- // GIVEN that the effect is at the middle of its completion (progress of 50%)
- animatorTestRule.advanceTimeBy(effectDuration / 2L)
-
- // WHEN an action cancel occurs
- longPressEffect.handleActionCancel()
-
- // THEN the effect gets reversed at 50% progress
- assertEffectReverses(0.5f)
- }
-
- @Test
- fun onAnimationComplete_keyguardDismissible_effectEndsWithLongPress() = testWhileRunning {
- // GIVEN that the animation completes
- animatorTestRule.advanceTimeBy(effectDuration + 10L)
-
- // THEN the long-press effect completes with a LONG_PRESS
- assertEffectCompleted(QSLongPressEffect.ActionType.LONG_PRESS)
- }
+ // THEN the long-press effect completes with a LONG_PRESS
+ assertEffectCompleted(QSLongPressEffect.ActionType.LONG_PRESS)
+ }
@Test
fun onAnimationComplete_keyguardNotDismissible_effectEndsWithResetAndLongPress() =
- testWhileRunning {
+ testWhileInState(QSLongPressEffect.State.RUNNING_FORWARD) {
// GIVEN that the keyguard is not dismissible
kosmos.fakeKeyguardRepository.setKeyguardDismissible(false)
// GIVEN that the animation completes
- animatorTestRule.advanceTimeBy(effectDuration + 10L)
+ longPressEffect.handleAnimationComplete()
// THEN the long-press effect completes with RESET_AND_LONG_PRESS
assertEffectCompleted(QSLongPressEffect.ActionType.RESET_AND_LONG_PRESS)
}
@Test
- fun onActionDown_whileRunningBackwards_resets() = testWhileRunning {
- // GIVEN that the effect is at the middle of its completion (progress of 50%)
- animatorTestRule.advanceTimeBy(effectDuration / 2L)
+ fun onActionDown_whileRunningBackwards_cancels() =
+ testWhileInState(QSLongPressEffect.State.RUNNING_FORWARD) {
+ // GIVEN an action cancel occurs and the effect gets reversed
+ longPressEffect.handleActionCancel()
- // GIVEN an action cancel occurs and the effect gets reversed
- longPressEffect.handleActionCancel()
+ // GIVEN an action down occurs
+ longPressEffect.handleActionDown()
- // GIVEN an action down occurs
- longPressEffect.handleActionDown()
-
- // THEN the effect resets
- assertEffectResets()
- }
+ // THEN the effect posts an action to cancel the animator
+ val action by collectLastValue(longPressEffect.actionType)
+ assertThat(action).isEqualTo(QSLongPressEffect.ActionType.CANCEL_ANIMATOR)
+ }
@Test
- fun onAnimationComplete_whileRunningBackwards_goesToIdle() = testWhileRunning {
- // GIVEN that the effect is at the middle of its completion (progress of 50%)
- animatorTestRule.advanceTimeBy(effectDuration / 2L)
+ fun onAnimatorCancel_effectGoesBackToWait() =
+ testWhileInState(QSLongPressEffect.State.RUNNING_FORWARD) {
+ // GIVEN that the animator was cancelled
+ longPressEffect.handleAnimationCancel()
- // GIVEN an action cancel occurs and the effect gets reversed
- longPressEffect.handleActionCancel()
+ // THEN the state goes to the timeout wait
+ assertThat(longPressEffect.state).isEqualTo(QSLongPressEffect.State.TIMEOUT_WAIT)
+ }
- // GIVEN that the animation completes after a sufficient amount of time
- animatorTestRule.advanceTimeBy(effectDuration.toLong())
+ @Test
+ fun onAnimationComplete_whileRunningBackwards_goesToIdle() =
+ testWhileInState(QSLongPressEffect.State.RUNNING_BACKWARDS) {
+ // GIVEN an action cancel occurs and the effect gets reversed
+ longPressEffect.handleActionCancel()
- // THEN the state goes to [QSLongPressEffect.State.IDLE]
- val state by collectLastValue(longPressEffect.state)
- assertThat(state).isEqualTo(QSLongPressEffect.State.IDLE)
- }
+ // GIVEN that the animation completes
+ longPressEffect.handleAnimationComplete()
- private fun testWithScope(test: suspend TestScope.() -> Unit) =
- with(kosmos) { testScope.runTest { test() } }
+ // THEN the state goes to [QSLongPressEffect.State.IDLE]
+ assertThat(longPressEffect.state).isEqualTo(QSLongPressEffect.State.IDLE)
+ }
- private fun testWhileWaiting(test: suspend TestScope.() -> Unit) =
+ private fun testWithScope(initialize: Boolean = true, test: suspend TestScope.() -> Unit) =
with(kosmos) {
testScope.runTest {
- // GIVEN the TIMEOUT_WAIT state is entered
- longPressEffect.setState(QSLongPressEffect.State.TIMEOUT_WAIT)
-
- // THEN run the test
+ if (initialize) {
+ longPressEffect.initializeEffect(effectDuration)
+ }
test()
}
}
- private fun testWhileRunning(test: suspend TestScope.() -> Unit) =
+ private fun testWhileInState(
+ state: QSLongPressEffect.State,
+ initialize: Boolean = true,
+ test: suspend TestScope.() -> Unit,
+ ) =
with(kosmos) {
testScope.runTest {
- // GIVEN that the effect starts after the tap timeout is complete
- longPressEffect.setState(QSLongPressEffect.State.TIMEOUT_WAIT)
- longPressEffect.handleTimeoutComplete()
+ if (initialize) {
+ longPressEffect.initializeEffect(effectDuration)
+ }
+ // GIVEN a state
+ longPressEffect.setState(state)
// THEN run the test
test()
@@ -270,13 +268,10 @@
/**
* Asserts that the effect started by checking that:
- * 1. The effect progress is 0f
- * 2. Initial hint haptics are played
- * 3. The internal state is [QSLongPressEffect.State.RUNNING_FORWARD]
+ * 1. Initial hint haptics are played
+ * 2. The internal state is [QSLongPressEffect.State.RUNNING_FORWARD]
*/
- private fun TestScope.assertEffectStarted() {
- val effectProgress by collectLastValue(longPressEffect.effectProgress)
- val state by collectLastValue(longPressEffect.state)
+ private fun assertEffectStarted() {
val longPressHint =
LongPressHapticBuilder.createLongPressHint(
lowTickDuration,
@@ -284,78 +279,48 @@
effectDuration,
)
- assertThat(state).isEqualTo(QSLongPressEffect.State.RUNNING_FORWARD)
- assertThat(effectProgress).isEqualTo(0f)
+ assertThat(longPressEffect.state).isEqualTo(QSLongPressEffect.State.RUNNING_FORWARD)
assertThat(longPressHint).isNotNull()
assertThat(vibratorHelper.hasVibratedWithEffects(longPressHint!!)).isTrue()
}
/**
* Asserts that the effect did not start by checking that:
- * 1. No effect progress is emitted
- * 2. No haptics are played
- * 3. The internal state is not [QSLongPressEffect.State.RUNNING_BACKWARDS] or
+ * 1. No haptics are played
+ * 2. The internal state is not [QSLongPressEffect.State.RUNNING_BACKWARDS] or
* [QSLongPressEffect.State.RUNNING_FORWARD]
*/
- private fun TestScope.assertEffectDidNotStart() {
- val effectProgress by collectLastValue(longPressEffect.effectProgress)
- val state by collectLastValue(longPressEffect.state)
-
- assertThat(state).isNotEqualTo(QSLongPressEffect.State.RUNNING_FORWARD)
- assertThat(state).isNotEqualTo(QSLongPressEffect.State.RUNNING_BACKWARDS)
- assertThat(effectProgress).isNull()
+ private fun assertEffectDidNotStart() {
+ assertThat(longPressEffect.state).isNotEqualTo(QSLongPressEffect.State.RUNNING_FORWARD)
+ assertThat(longPressEffect.state).isNotEqualTo(QSLongPressEffect.State.RUNNING_BACKWARDS)
assertThat(vibratorHelper.totalVibrations).isEqualTo(0)
}
/**
* Asserts that the effect completes by checking that:
- * 1. The progress is null
- * 2. The final snap haptics are played
- * 3. The internal state goes back to [QSLongPressEffect.State.IDLE]
- * 4. The action to perform on the tile is the action given as a parameter
+ * 1. The final snap haptics are played
+ * 2. The internal state goes back to [QSLongPressEffect.State.IDLE]
+ * 3. The action to perform on the tile is the action given as a parameter
*/
private fun TestScope.assertEffectCompleted(expectedAction: QSLongPressEffect.ActionType) {
val action by collectLastValue(longPressEffect.actionType)
- val effectProgress by collectLastValue(longPressEffect.effectProgress)
val snapEffect = LongPressHapticBuilder.createSnapEffect()
- val state by collectLastValue(longPressEffect.state)
- assertThat(effectProgress).isNull()
assertThat(snapEffect).isNotNull()
assertThat(vibratorHelper.hasVibratedWithEffects(snapEffect!!)).isTrue()
- assertThat(state).isEqualTo(QSLongPressEffect.State.IDLE)
+ assertThat(longPressEffect.state).isEqualTo(QSLongPressEffect.State.IDLE)
assertThat(action).isEqualTo(expectedAction)
}
/**
* Assert that the effect gets reverted by checking that:
* 1. The internal state is [QSLongPressEffect.State.RUNNING_BACKWARDS]
- * 2. The reverse haptics plays at the point where the animation was paused
+ * 2. An action to reverse the animator is emitted
*/
- private fun TestScope.assertEffectReverses(pausedProgress: Float) {
- val reverseHaptics =
- LongPressHapticBuilder.createReversedEffect(
- pausedProgress,
- lowTickDuration,
- effectDuration,
- )
- val state by collectLastValue(longPressEffect.state)
+ private fun TestScope.assertEffectReverses() {
+ val action by collectLastValue(longPressEffect.actionType)
- assertThat(state).isEqualTo(QSLongPressEffect.State.RUNNING_BACKWARDS)
- assertThat(reverseHaptics).isNotNull()
- assertThat(vibratorHelper.hasVibratedWithEffects(reverseHaptics!!)).isTrue()
- }
-
- /**
- * Asserts that the effect resets by checking that:
- * 1. The effect progress resets to 0
- * 2. The internal state goes back to [QSLongPressEffect.State.TIMEOUT_WAIT]
- */
- private fun TestScope.assertEffectResets() {
- val effectProgress by collectLastValue(longPressEffect.effectProgress)
- val state by collectLastValue(longPressEffect.state)
-
- assertThat(effectProgress).isNull()
- assertThat(state).isEqualTo(QSLongPressEffect.State.TIMEOUT_WAIT)
+ assertThat(longPressEffect.state).isEqualTo(QSLongPressEffect.State.RUNNING_BACKWARDS)
+ assertThat(action).isEqualTo(QSLongPressEffect.ActionType.REVERSE_ANIMATOR)
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModelTest.kt
index 31337a6..e270d9e 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModelTest.kt
@@ -28,6 +28,7 @@
import com.android.systemui.keyguard.domain.interactor.BurnInInteractor
import com.android.systemui.keyguard.domain.interactor.burnInInteractor
import com.android.systemui.keyguard.shared.model.BurnInModel
+import com.android.systemui.keyguard.shared.model.ClockSize
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionStep
@@ -59,6 +60,7 @@
private val kosmos = testKosmos()
private val testScope = kosmos.testScope
private val keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository
+ private val keyguardClockRepository = kosmos.fakeKeyguardClockRepository
private lateinit var underTest: AodBurnInViewModel
private var burnInParameters = BurnInParameters()
@@ -67,6 +69,7 @@
@Before
fun setUp() {
mSetFlagsRule.disableFlags(AConfigFlags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT)
+ mSetFlagsRule.disableFlags(AConfigFlags.FLAG_COMPOSE_LOCKSCREEN)
MockitoAnnotations.initMocks(this)
whenever(burnInInteractor.burnIn(anyInt(), anyInt())).thenReturn(burnInFlow)
@@ -298,4 +301,80 @@
assertThat(movement?.scale).isEqualTo(0.5f)
assertThat(movement?.scaleClockOnly).isEqualTo(false)
}
+
+ @Test
+ fun translationAndScale_composeFlagOn_weatherLargeClock() =
+ testBurnInViewModelWhenComposeFlagOn(
+ isSmallClock = false,
+ isWeatherClock = true,
+ expectedScaleOnly = false
+ )
+
+ @Test
+ fun translationAndScale_composeFlagOn_weatherSmallClock() =
+ testBurnInViewModelWhenComposeFlagOn(
+ isSmallClock = true,
+ isWeatherClock = true,
+ expectedScaleOnly = true
+ )
+
+ @Test
+ fun translationAndScale_composeFlagOn_nonWeatherLargeClock() =
+ testBurnInViewModelWhenComposeFlagOn(
+ isSmallClock = false,
+ isWeatherClock = false,
+ expectedScaleOnly = true
+ )
+
+ @Test
+ fun translationAndScale_composeFlagOn_nonWeatherSmallClock() =
+ testBurnInViewModelWhenComposeFlagOn(
+ isSmallClock = true,
+ isWeatherClock = false,
+ expectedScaleOnly = true
+ )
+
+ private fun testBurnInViewModelWhenComposeFlagOn(
+ isSmallClock: Boolean,
+ isWeatherClock: Boolean,
+ expectedScaleOnly: Boolean
+ ) =
+ testScope.runTest {
+ mSetFlagsRule.enableFlags(AConfigFlags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT)
+ mSetFlagsRule.enableFlags(AConfigFlags.FLAG_COMPOSE_LOCKSCREEN)
+ if (isSmallClock) {
+ keyguardClockRepository.setClockSize(ClockSize.SMALL)
+ // we need the following step to update stateFlow value
+ kosmos.testScope.collectLastValue(kosmos.keyguardClockViewModel.clockSize)
+ }
+
+ whenever(clockController.config.useAlternateSmartspaceAODTransition)
+ .thenReturn(if (isWeatherClock) true else false)
+
+ val movement by collectLastValue(underTest.movement(burnInParameters))
+
+ // Set to dozing (on AOD)
+ keyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.AOD,
+ value = 1f,
+ transitionState = TransitionState.FINISHED
+ ),
+ validateStep = false,
+ )
+
+ // Trigger a change to the burn-in model
+ burnInFlow.value =
+ BurnInModel(
+ translationX = 20,
+ translationY = 30,
+ scale = 0.5f,
+ )
+
+ assertThat(movement?.translationX).isEqualTo(20)
+ assertThat(movement?.translationY).isEqualTo(30)
+ assertThat(movement?.scale).isEqualTo(0.5f)
+ assertThat(movement?.scaleClockOnly).isEqualTo(expectedScaleOnly)
+ }
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt
index 719828c..d2a458c 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt
@@ -29,6 +29,7 @@
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.deviceentry.data.repository.fakeDeviceEntryRepository
import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor
+import com.android.systemui.flags.EnableSceneContainer
import com.android.systemui.flags.Flags
import com.android.systemui.flags.fakeFeatureFlagsClassic
import com.android.systemui.keyguard.data.repository.fakeDeviceEntryFingerprintAuthRepository
@@ -38,6 +39,8 @@
import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsViewModel
import com.android.systemui.qs.ui.adapter.FakeQSSceneAdapter
import com.android.systemui.res.R
+import com.android.systemui.scene.domain.interactor.sceneBackInteractor
+import com.android.systemui.scene.domain.interactor.sceneContainerStartable
import com.android.systemui.scene.domain.interactor.sceneInteractor
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.settings.brightness.ui.viewmodel.brightnessMirrorViewModel
@@ -58,6 +61,7 @@
@SmallTest
@RunWith(AndroidJUnit4::class)
+@EnableSceneContainer
class QuickSettingsSceneViewModelTest : SysuiTestCase() {
private val kosmos = testKosmos()
@@ -71,6 +75,8 @@
private val footerActionsController = mock<FooterActionsController>()
private val sceneInteractor = kosmos.sceneInteractor
+ private val sceneBackInteractor = kosmos.sceneBackInteractor
+ private val sceneContainerStartable = kosmos.sceneContainerStartable
private lateinit var underTest: QuickSettingsSceneViewModel
@@ -79,6 +85,7 @@
fun setUp() {
kosmos.fakeFeatureFlagsClassic.set(Flags.NEW_NETWORK_SLICE_UI, false)
+ sceneContainerStartable.start()
underTest =
QuickSettingsSceneViewModel(
applicationScope = testScope.backgroundScope,
@@ -89,7 +96,7 @@
notifications = kosmos.notificationsPlaceholderViewModel,
footerActionsViewModelFactory = footerActionsViewModelFactory,
footerActionsController = footerActionsController,
- sceneInteractor = sceneInteractor,
+ sceneBackInteractor = sceneBackInteractor,
)
}
@@ -127,11 +134,12 @@
val destinations by collectLastValue(underTest.destinationScenes)
val currentScene by collectLastValue(sceneInteractor.currentScene)
- val previousScene by collectLastValue(sceneInteractor.previousScene())
+ val backScene by collectLastValue(sceneBackInteractor.backScene)
sceneInteractor.changeScene(Scenes.Lockscreen, "reason")
sceneInteractor.changeScene(Scenes.QuickSettings, "reason")
assertThat(currentScene).isEqualTo(Scenes.QuickSettings)
- assertThat(previousScene).isEqualTo(Scenes.Lockscreen)
+ assertThat(backScene).isEqualTo(Scenes.Lockscreen)
+
assertThat(destinations)
.isEqualTo(
mapOf(
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/data/repository/SceneContainerRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/data/repository/SceneContainerRepositoryTest.kt
index 8e2eea1..a45ac9f 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/data/repository/SceneContainerRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/data/repository/SceneContainerRepositoryTest.kt
@@ -140,23 +140,4 @@
ObservableTransitionState.Idle(kosmos.sceneContainerConfig.initialSceneKey)
)
}
-
- @Test
- fun previousScene() =
- testScope.runTest {
- val underTest = kosmos.sceneContainerRepository
- val currentScene by collectLastValue(underTest.currentScene)
- val previousScene by collectLastValue(underTest.previousScene)
-
- assertThat(previousScene).isNull()
-
- val firstScene = currentScene
- underTest.changeScene(Scenes.Shade)
- assertThat(previousScene).isEqualTo(firstScene)
- assertThat(currentScene).isEqualTo(Scenes.Shade)
-
- underTest.changeScene(Scenes.QuickSettings)
- assertThat(previousScene).isEqualTo(Scenes.Shade)
- assertThat(currentScene).isEqualTo(Scenes.QuickSettings)
- }
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneBackInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneBackInteractorTest.kt
new file mode 100644
index 0000000..c75e297
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneBackInteractorTest.kt
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+@file:OptIn(ExperimentalCoroutinesApi::class)
+
+package com.android.systemui.scene.domain.interactor
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.compose.animation.scene.SceneKey
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.authentication.data.repository.FakeAuthenticationRepository
+import com.android.systemui.authentication.domain.interactor.AuthenticationResult
+import com.android.systemui.authentication.domain.interactor.authenticationInteractor
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.flags.EnableSceneContainer
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.scene.shared.model.Scenes
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import com.google.common.truth.Truth.assertWithMessage
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class SceneBackInteractorTest : SysuiTestCase() {
+
+ private val kosmos = testKosmos()
+ private val testScope = kosmos.testScope
+ private val sceneInteractor = kosmos.sceneInteractor
+ private val sceneContainerStartable = kosmos.sceneContainerStartable
+ private val authenticationInteractor = kosmos.authenticationInteractor
+
+ private val underTest = kosmos.sceneBackInteractor
+
+ @Test
+ @EnableSceneContainer
+ fun navigateToQs_thenBouncer_thenBack_whileLocked() =
+ testScope.runTest {
+ sceneContainerStartable.start()
+
+ assertRoute(
+ RouteNode(Scenes.Lockscreen, null),
+ RouteNode(Scenes.Shade, Scenes.Lockscreen),
+ RouteNode(Scenes.QuickSettings, Scenes.Shade),
+ RouteNode(Scenes.Bouncer, Scenes.QuickSettings),
+ RouteNode(Scenes.QuickSettings, Scenes.Shade),
+ RouteNode(Scenes.Shade, Scenes.Lockscreen),
+ RouteNode(Scenes.Lockscreen, null),
+ )
+ }
+
+ @Test
+ @EnableSceneContainer
+ fun navigateToQs_thenBouncer_thenUnlock() =
+ testScope.runTest {
+ sceneContainerStartable.start()
+
+ assertRoute(
+ RouteNode(Scenes.Lockscreen, null),
+ RouteNode(Scenes.Shade, Scenes.Lockscreen),
+ RouteNode(Scenes.QuickSettings, Scenes.Shade),
+ RouteNode(Scenes.Bouncer, Scenes.QuickSettings, unlockDevice = true),
+ RouteNode(Scenes.Gone, null),
+ )
+ }
+
+ @Test
+ @EnableSceneContainer
+ fun navigateToQs_skippingShade_thenBouncer_thenBack_whileLocked() =
+ testScope.runTest {
+ sceneContainerStartable.start()
+
+ assertRoute(
+ RouteNode(Scenes.Lockscreen, null),
+ RouteNode(Scenes.QuickSettings, Scenes.Lockscreen),
+ RouteNode(Scenes.Bouncer, Scenes.QuickSettings),
+ RouteNode(Scenes.QuickSettings, Scenes.Lockscreen),
+ RouteNode(Scenes.Lockscreen, null),
+ )
+ }
+
+ @Test
+ @EnableSceneContainer
+ fun navigateToBouncer_thenBack_whileLocked() =
+ testScope.runTest {
+ sceneContainerStartable.start()
+
+ assertRoute(
+ RouteNode(Scenes.Lockscreen, null),
+ RouteNode(Scenes.Bouncer, Scenes.Lockscreen),
+ RouteNode(Scenes.Lockscreen, null),
+ )
+ }
+
+ @Test
+ @EnableSceneContainer
+ fun navigateToQs_skippingShade_thenBouncer_thenBack_thenShade_whileLocked() =
+ testScope.runTest {
+ sceneContainerStartable.start()
+
+ assertRoute(
+ RouteNode(Scenes.Lockscreen, null),
+ RouteNode(Scenes.QuickSettings, Scenes.Lockscreen),
+ RouteNode(Scenes.Bouncer, Scenes.QuickSettings),
+ RouteNode(Scenes.QuickSettings, Scenes.Lockscreen),
+ RouteNode(Scenes.Lockscreen, null),
+ RouteNode(Scenes.Shade, Scenes.Lockscreen),
+ )
+ }
+
+ @Test
+ @EnableSceneContainer
+ fun navigateToQs_thenBack_whileUnlocked() =
+ testScope.runTest {
+ sceneContainerStartable.start()
+ unlockDevice()
+
+ assertRoute(
+ RouteNode(Scenes.Gone, null),
+ RouteNode(Scenes.Shade, Scenes.Gone),
+ RouteNode(Scenes.QuickSettings, Scenes.Shade),
+ RouteNode(Scenes.Shade, Scenes.Gone),
+ RouteNode(Scenes.Gone, null),
+ )
+ }
+
+ @Test
+ @EnableSceneContainer
+ fun navigateToQs_skippingShade_thenBack_whileUnlocked() =
+ testScope.runTest {
+ sceneContainerStartable.start()
+ unlockDevice()
+
+ assertRoute(
+ RouteNode(Scenes.Gone, null),
+ RouteNode(Scenes.QuickSettings, Scenes.Gone),
+ RouteNode(Scenes.Gone, null),
+ )
+ }
+
+ @Test
+ @EnableSceneContainer
+ fun navigateToQs_skippingShade_thenBack_thenShade_whileUnlocked() =
+ testScope.runTest {
+ sceneContainerStartable.start()
+ unlockDevice()
+
+ assertRoute(
+ RouteNode(Scenes.Gone, null),
+ RouteNode(Scenes.QuickSettings, Scenes.Gone),
+ RouteNode(Scenes.Gone, null),
+ RouteNode(Scenes.Shade, Scenes.Gone),
+ )
+ }
+
+ private suspend fun TestScope.assertRoute(vararg route: RouteNode) {
+ val currentScene by collectLastValue(sceneInteractor.currentScene)
+ val backScene by collectLastValue(underTest.backScene)
+
+ route.forEachIndexed { index, node ->
+ sceneInteractor.changeScene(node.changeSceneTo, "")
+ assertWithMessage("node at index $index currentScene mismatch")
+ .that(currentScene)
+ .isEqualTo(node.changeSceneTo)
+ assertWithMessage("node at index $index backScene mismatch")
+ .that(backScene)
+ .isEqualTo(node.expectedBackScene)
+ if (node.unlockDevice) {
+ unlockDevice()
+ }
+ }
+ }
+
+ private suspend fun TestScope.unlockDevice() {
+ val currentScene by collectLastValue(sceneInteractor.currentScene)
+ runCurrent()
+ assertThat(authenticationInteractor.authenticate(FakeAuthenticationRepository.DEFAULT_PIN))
+ .isEqualTo(AuthenticationResult.SUCCEEDED)
+ assertThat(currentScene).isEqualTo(Scenes.Gone)
+ }
+
+ private data class RouteNode(
+ val changeSceneTo: SceneKey,
+ val expectedBackScene: SceneKey? = null,
+ val unlockDevice: Boolean = false,
+ )
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt
index 871ce6d..2fb8212 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt
@@ -291,34 +291,4 @@
assertThat(isVisible).isFalse()
}
-
- @Test
- fun previousScene() =
- testScope.runTest {
- val currentScene by collectLastValue(underTest.currentScene)
- val previousScene by collectLastValue(underTest.previousScene())
- assertThat(previousScene).isNull()
-
- val firstScene = currentScene
- underTest.changeScene(toScene = Scenes.Shade, "reason")
- assertThat(previousScene).isEqualTo(firstScene)
-
- underTest.changeScene(toScene = Scenes.QuickSettings, "reason")
- assertThat(previousScene).isEqualTo(Scenes.Shade)
- }
-
- @Test
- fun previousScene_withIgnoredScene() =
- testScope.runTest {
- val currentScene by collectLastValue(underTest.currentScene)
- val previousScene by collectLastValue(underTest.previousScene(ignored = Scenes.Shade))
- assertThat(previousScene).isNull()
-
- val firstScene = currentScene
- underTest.changeScene(toScene = Scenes.Shade, "reason")
- assertThat(previousScene).isEqualTo(firstScene)
-
- underTest.changeScene(toScene = Scenes.QuickSettings, "reason")
- assertThat(previousScene).isNull()
- }
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
index 2586ad541..5779e37 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
@@ -392,6 +392,7 @@
Scenes.Gone,
Scenes.Lockscreen,
Scenes.Bouncer,
+ Scenes.Gone,
Scenes.Shade,
Scenes.QuickSettings,
)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java
index a8da116..e160cfc 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java
@@ -79,12 +79,12 @@
import org.mockito.MockitoAnnotations;
import org.mockito.Spy;
-import java.util.List;
-import java.util.concurrent.Executor;
-
import platform.test.runner.parameterized.ParameterizedAndroidJunit4;
import platform.test.runner.parameterized.Parameters;
+import java.util.List;
+import java.util.concurrent.Executor;
+
@RunWith(ParameterizedAndroidJunit4.class)
@RunWithLooper(setAsMainLooper = true)
@SmallTest
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
index 7fabe33..02993b8 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar;
+import static android.app.Flags.FLAG_KEYGUARD_PRIVATE_NOTIFICATIONS;
import static android.app.Notification.VISIBILITY_PRIVATE;
import static android.app.NotificationManager.IMPORTANCE_HIGH;
import static android.app.NotificationManager.VISIBILITY_NO_OVERRIDE;
@@ -24,7 +25,6 @@
import static android.app.admin.DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED;
import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_SECURE_NOTIFICATIONS;
import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS;
-import static android.app.Flags.FLAG_KEYGUARD_PRIVATE_NOTIFICATIONS;
import static android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES;
import static android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE;
import static android.os.UserHandle.USER_ALL;
@@ -73,7 +73,6 @@
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FakeFeatureFlagsClassic;
-import com.android.systemui.flags.Flags;
import com.android.systemui.log.LogWtfHandlerRule;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.recents.OverviewProxyService;
@@ -100,14 +99,14 @@
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
+import platform.test.runner.parameterized.ParameterizedAndroidJunit4;
+import platform.test.runner.parameterized.Parameters;
+
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.Executor;
-import platform.test.runner.parameterized.ParameterizedAndroidJunit4;
-import platform.test.runner.parameterized.Parameters;
-
@SmallTest
@RunWith(ParameterizedAndroidJunit4.class)
public class NotificationLockscreenUserManagerTest extends SysuiTestCase {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/AvalancheControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/AvalancheControllerTest.kt
index 7420ea0..8ce5037 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/AvalancheControllerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/AvalancheControllerTest.kt
@@ -30,7 +30,7 @@
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.settings.FakeGlobalSettings
import com.android.systemui.util.time.FakeSystemClock
-import com.google.common.truth.Truth
+import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Rule
import org.junit.Test
@@ -132,7 +132,7 @@
mAvalancheController.update(headsUpEntry, runnableMock!!, "testLabel")
// Entry is showing now
- Truth.assertThat(mAvalancheController.headsUpEntryShowing).isEqualTo(headsUpEntry)
+ assertThat(mAvalancheController.headsUpEntryShowing).isEqualTo(headsUpEntry)
}
@Test
@@ -147,14 +147,14 @@
// Entry has one Runnable
val runnableList: List<Runnable?>? = mAvalancheController.nextMap[headsUpEntry]
- Truth.assertThat(runnableList).isNotNull()
- Truth.assertThat(runnableList!!.size).isEqualTo(1)
+ assertThat(runnableList).isNotNull()
+ assertThat(runnableList!!.size).isEqualTo(1)
// Update
mAvalancheController.update(headsUpEntry, runnableMock, "testLabel")
// Entry has two Runnables
- Truth.assertThat(runnableList.size).isEqualTo(2)
+ assertThat(runnableList.size).isEqualTo(2)
}
@Test
@@ -172,7 +172,7 @@
mAvalancheController.update(headsUpEntry, runnableMock!!, "testLabel")
// Entry is next
- Truth.assertThat(mAvalancheController.nextMap.containsKey(headsUpEntry)).isTrue()
+ assertThat(mAvalancheController.nextMap.containsKey(headsUpEntry)).isTrue()
}
@Test
@@ -185,7 +185,7 @@
mAvalancheController.delete(headsUpEntry, runnableMock, "testLabel")
// Entry was removed from next
- Truth.assertThat(mAvalancheController.nextMap.containsKey(headsUpEntry)).isFalse()
+ assertThat(mAvalancheController.nextMap.containsKey(headsUpEntry)).isFalse()
// Runnable was not run
Mockito.verify(runnableMock, Mockito.times(0)).run()
@@ -201,7 +201,7 @@
mAvalancheController.delete(headsUpEntry, runnableMock!!, "testLabel")
// Entry was removed from dropSet
- Truth.assertThat(mAvalancheController.debugDropSet.contains(headsUpEntry)).isFalse()
+ assertThat(mAvalancheController.debugDropSet.contains(headsUpEntry)).isFalse()
}
@Test
@@ -244,7 +244,27 @@
mAvalancheController.delete(showingEntry, runnableMock, "testLabel")
// Next entry is shown
- Truth.assertThat(mAvalancheController.headsUpEntryShowing).isEqualTo(nextEntry)
+ assertThat(mAvalancheController.headsUpEntryShowing).isEqualTo(nextEntry)
+ }
+
+
+ @Test
+ fun testDelete_showingEntryKeyBecomesPreviousHunKey() {
+ mAvalancheController.previousHunKey = ""
+
+ // Entry is showing
+ val showingEntry = createHeadsUpEntry(id = 0)
+ mAvalancheController.headsUpEntryShowing = showingEntry
+
+ // There's another entry waiting to show next
+ val nextEntry = createHeadsUpEntry(id = 1)
+ mAvalancheController.addToNext(nextEntry, runnableMock!!)
+
+ // Delete
+ mAvalancheController.delete(showingEntry, runnableMock, "testLabel")
+
+ // Next entry is shown
+ assertThat(mAvalancheController.previousHunKey).isEqualTo(showingEntry.mEntry!!.key)
}
@Test
@@ -258,7 +278,7 @@
mAvalancheController.clearNext()
val durationMs = mAvalancheController.getDurationMs(givenEntry, autoDismissMs = 5000)
- Truth.assertThat(durationMs).isEqualTo(5000)
+ assertThat(durationMs).isEqualTo(5000)
}
@Test
@@ -273,7 +293,7 @@
mAvalancheController.addToNext(nextEntry, runnableMock!!)
val durationMs = mAvalancheController.getDurationMs(givenEntry, autoDismissMs = 5000)
- Truth.assertThat(durationMs).isEqualTo(5000)
+ assertThat(durationMs).isEqualTo(5000)
}
@Test
@@ -286,7 +306,7 @@
mAvalancheController.clearNext()
val durationMs = mAvalancheController.getDurationMs(showingEntry, autoDismissMs = 5000)
- Truth.assertThat(durationMs).isEqualTo(5000)
+ assertThat(durationMs).isEqualTo(5000)
}
@Test
@@ -300,10 +320,10 @@
mAvalancheController.addToNext(nextEntry, runnableMock!!)
// Next entry has lower priority
- Truth.assertThat(nextEntry.compareNonTimeFields(showingEntry)).isEqualTo(1)
+ assertThat(nextEntry.compareNonTimeFields(showingEntry)).isEqualTo(1)
val durationMs = mAvalancheController.getDurationMs(showingEntry, autoDismissMs = 5000)
- Truth.assertThat(durationMs).isEqualTo(5000)
+ assertThat(durationMs).isEqualTo(5000)
}
@Test
@@ -317,10 +337,10 @@
mAvalancheController.addToNext(nextEntry, runnableMock!!)
// Same priority
- Truth.assertThat(nextEntry.compareNonTimeFields(showingEntry)).isEqualTo(0)
+ assertThat(nextEntry.compareNonTimeFields(showingEntry)).isEqualTo(0)
val durationMs = mAvalancheController.getDurationMs(showingEntry, autoDismissMs = 5000)
- Truth.assertThat(durationMs).isEqualTo(1000)
+ assertThat(durationMs).isEqualTo(1000)
}
@Test
@@ -334,9 +354,9 @@
mAvalancheController.addToNext(nextEntry, runnableMock!!)
// Next entry has higher priority
- Truth.assertThat(nextEntry.compareNonTimeFields(showingEntry)).isEqualTo(-1)
+ assertThat(nextEntry.compareNonTimeFields(showingEntry)).isEqualTo(-1)
val durationMs = mAvalancheController.getDurationMs(showingEntry, autoDismissMs = 5000)
- Truth.assertThat(durationMs).isEqualTo(500)
+ assertThat(durationMs).isEqualTo(500)
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/BaseHeadsUpManagerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/BaseHeadsUpManagerTest.java
index db8e14c1..0f66a93 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/BaseHeadsUpManagerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/BaseHeadsUpManagerTest.java
@@ -62,11 +62,11 @@
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
-import java.util.List;
-
import platform.test.runner.parameterized.ParameterizedAndroidJunit4;
import platform.test.runner.parameterized.Parameters;
+import java.util.List;
+
@SmallTest
@TestableLooper.RunWithLooper
@RunWith(ParameterizedAndroidJunit4.class)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerPhoneTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerPhoneTest.java
index f66e75a..9feb914 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerPhoneTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerPhoneTest.java
@@ -49,6 +49,8 @@
import com.android.systemui.util.settings.GlobalSettings;
import com.android.systemui.util.time.SystemClock;
+import kotlinx.coroutines.flow.StateFlowKt;
+
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Rule;
@@ -58,12 +60,11 @@
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
-import java.util.List;
-
-import kotlinx.coroutines.flow.StateFlowKt;
import platform.test.runner.parameterized.ParameterizedAndroidJunit4;
import platform.test.runner.parameterized.Parameters;
+import java.util.List;
+
@SmallTest
@RunWith(ParameterizedAndroidJunit4.class)
@TestableLooper.RunWithLooper
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTestUtil.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTestUtil.java
index bda8619..306d6efd 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTestUtil.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTestUtil.java
@@ -16,13 +16,12 @@
package com.android.systemui.statusbar.policy;
import android.app.ActivityManager;
+import android.app.Notification;
import android.app.PendingIntent;
+import android.content.Context;
import android.content.Intent;
import android.os.UserHandle;
-
-import android.content.Context;
import android.service.notification.StatusBarNotification;
-import android.app.Notification;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
diff --git a/packages/SystemUI/plugin/ExamplePlugin/src/com/android/systemui/plugin/testoverlayplugin/SampleOverlayPlugin.java b/packages/SystemUI/plugin/ExamplePlugin/src/com/android/systemui/plugin/testoverlayplugin/SampleOverlayPlugin.java
index 79a0c35..4a0626c 100644
--- a/packages/SystemUI/plugin/ExamplePlugin/src/com/android/systemui/plugin/testoverlayplugin/SampleOverlayPlugin.java
+++ b/packages/SystemUI/plugin/ExamplePlugin/src/com/android/systemui/plugin/testoverlayplugin/SampleOverlayPlugin.java
@@ -20,9 +20,9 @@
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-
import android.view.ViewTreeObserver.InternalInsetsInfo;
import android.view.ViewTreeObserver.OnComputeInternalInsetsListener;
+
import com.android.systemui.plugins.OverlayPlugin;
import com.android.systemui.plugins.annotations.Requires;
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/IntentButtonProvider.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/IntentButtonProvider.java
index 97dbafd..63bb24f 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/IntentButtonProvider.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/IntentButtonProvider.java
@@ -14,11 +14,11 @@
package com.android.systemui.plugins;
-import com.android.systemui.plugins.annotations.ProvidesInterface;
-
import android.content.Intent;
import android.graphics.drawable.Drawable;
+import com.android.systemui.plugins.annotations.ProvidesInterface;
+
/**
* An Intent Button represents a triggerable element in SysUI that consists of an
* Icon and an intent to trigger when it is activated (clicked, swiped, etc.).
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/NotificationPersonExtractorPlugin.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/NotificationPersonExtractorPlugin.java
index f79cd86..4113c04 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/NotificationPersonExtractorPlugin.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/NotificationPersonExtractorPlugin.java
@@ -17,7 +17,6 @@
package com.android.systemui.plugins;
import android.annotation.Nullable;
-import android.app.PendingIntent;
import android.graphics.drawable.Drawable;
import android.service.notification.StatusBarNotification;
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginUtils.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginUtils.java
index af49d43..acb6f11 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginUtils.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginUtils.java
@@ -15,7 +15,6 @@
package com.android.systemui.plugins;
import android.content.Context;
-import android.view.LayoutInflater;
import android.view.View;
public class PluginUtils {
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/StatusBarStateController.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/StatusBarStateController.java
index 02085b9..4c5ca2fd 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/StatusBarStateController.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/StatusBarStateController.java
@@ -19,7 +19,6 @@
import com.android.systemui.plugins.annotations.DependsOn;
import com.android.systemui.plugins.annotations.ProvidesInterface;
-
/**
* Sends updates to {@link StateListener}s about changes to the status bar state and dozing state
*/
diff --git a/packages/SystemUI/plugin_core/src/com/android/systemui/plugins/Plugin.java b/packages/SystemUI/plugin_core/src/com/android/systemui/plugins/Plugin.java
index bb93367..8ff6c11 100644
--- a/packages/SystemUI/plugin_core/src/com/android/systemui/plugins/Plugin.java
+++ b/packages/SystemUI/plugin_core/src/com/android/systemui/plugins/Plugin.java
@@ -13,10 +13,10 @@
*/
package com.android.systemui.plugins;
-import com.android.systemui.plugins.annotations.Requires;
-
import android.content.Context;
+import com.android.systemui.plugins.annotations.Requires;
+
/**
* Plugins are separate APKs that
* are expected to implement interfaces provided by SystemUI. Their
diff --git a/packages/SystemUI/res/drawable/face_dialog_dark_to_checkmark.xml b/packages/SystemUI/res/drawable/face_dialog_dark_to_checkmark.xml
index fe19516..fb30249 100644
--- a/packages/SystemUI/res/drawable/face_dialog_dark_to_checkmark.xml
+++ b/packages/SystemUI/res/drawable/face_dialog_dark_to_checkmark.xml
@@ -40,7 +40,7 @@
<path
android:name="_R_G_L_0_G_D_0_P_0"
android:fillAlpha="0"
- android:fillColor="@color/biometric_dialog_accent"
+ android:fillColor="@color/biometric_dialog_face_checkmark"
android:fillType="nonZero"
android:pathData=" M-116 -16.5 C-116,-16.5 -31.25,68.5 -31.25,68.5 C-31.25,68.5 108.75,-71.5 108.75,-71.5 "
android:trimPathStart="0"
@@ -58,7 +58,7 @@
android:pathData=" M-116 -16.5 C-116,-16.5 -31.25,68.5 -31.25,68.5 C-31.25,68.5 108.75,-71.5 108.75,-71.5 "
android:strokeWidth="20"
android:strokeAlpha="1"
- android:strokeColor="@color/biometric_dialog_accent"
+ android:strokeColor="@color/biometric_dialog_face_checkmark"
android:trimPathStart="0"
android:trimPathEnd="0"
android:trimPathOffset="0" />
@@ -68,7 +68,7 @@
android:pathData=" M30 6.2 C16.9,6.2 6.3,16.8 6.3,30 C6.3,43.2 16.9,53.8 30,53.8 C43.1,53.8 53.8,43.2 53.8,30 C53.8,16.8 43.1,6.2 30,6.2c "
android:strokeWidth="2.5"
android:strokeAlpha="1"
- android:strokeColor="@color/biometric_dialog_accent"
+ android:strokeColor="@color/biometric_dialog_face_checkmark"
android:trimPathStart="0"
android:trimPathEnd="1"
android:trimPathOffset="0" />
@@ -387,7 +387,7 @@
android:propertyName="strokeColor"
android:startOffset="0"
android:valueFrom="@color/biometric_dialog_accent"
- android:valueTo="@color/biometric_dialog_accent"
+ android:valueTo="@color/biometric_dialog_face_checkmark"
android:valueType="colorType">
<aapt:attr name="android:interpolator">
<pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
@@ -398,7 +398,7 @@
android:propertyName="strokeColor"
android:startOffset="67"
android:valueFrom="@color/biometric_dialog_accent"
- android:valueTo="@color/biometric_dialog_accent"
+ android:valueTo="@color/biometric_dialog_face_checkmark"
android:valueType="colorType">
<aapt:attr name="android:interpolator">
<pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
diff --git a/packages/SystemUI/res/layout/screenshot_shelf.xml b/packages/SystemUI/res/layout/screenshot_shelf.xml
index 26d3f43..79b82bf 100644
--- a/packages/SystemUI/res/layout/screenshot_shelf.xml
+++ b/packages/SystemUI/res/layout/screenshot_shelf.xml
@@ -59,7 +59,7 @@
android:layout_marginTop="@dimen/overlay_border_width_neg"
android:layout_marginEnd="@dimen/overlay_border_width_neg"
android:layout_marginBottom="@dimen/screenshot_shelf_vertical_margin"
- android:elevation="8dp"
+ android:elevation="4dp"
android:background="@drawable/overlay_border"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/screenshot_preview"
@@ -72,7 +72,7 @@
android:layout_marginStart="@dimen/overlay_border_width"
android:layout_marginBottom="@dimen/overlay_border_width"
android:layout_gravity="center"
- android:elevation="8dp"
+ android:elevation="4dp"
android:contentDescription="@string/screenshot_edit_description"
android:scaleType="fitEnd"
android:background="@drawable/overlay_preview_background"
@@ -85,14 +85,14 @@
android:layout_width="56dp"
android:layout_height="56dp"
android:visibility="gone"
- android:elevation="9dp"
+ android:elevation="5dp"
app:layout_constraintBottom_toBottomOf="@id/screenshot_preview_border"
app:layout_constraintEnd_toEndOf="@id/screenshot_preview_border"/>
<FrameLayout
android:id="@+id/screenshot_dismiss_button"
android:layout_width="@dimen/overlay_dismiss_button_tappable_size"
android:layout_height="@dimen/overlay_dismiss_button_tappable_size"
- android:elevation="11dp"
+ android:elevation="7dp"
android:visibility="gone"
app:layout_constraintStart_toEndOf="@id/screenshot_preview"
app:layout_constraintEnd_toEndOf="@id/screenshot_preview"
diff --git a/packages/SystemUI/res/values-night/colors.xml b/packages/SystemUI/res/values-night/colors.xml
index 61a323d4..d377e01 100644
--- a/packages/SystemUI/res/values-night/colors.xml
+++ b/packages/SystemUI/res/values-night/colors.xml
@@ -77,6 +77,7 @@
<color name="biometric_dialog_gray">#ffcccccc</color>
<color name="biometric_dialog_accent">@color/material_dynamic_primary70</color>
<color name="biometric_dialog_error">#fff28b82</color> <!-- red 300 -->
+ <color name="biometric_dialog_face_checkmark">#5bb974</color> <!-- green 400 -->
<color name="GM2_green_500">#FF41Af6A</color>
<color name="GM2_blue_500">#5195EA</color>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 590dc68..ba59c2f9 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -140,6 +140,7 @@
<color name="biometric_dialog_gray">#ff757575</color>
<color name="biometric_dialog_accent">@color/material_dynamic_primary40</color>
<color name="biometric_dialog_error">#ffd93025</color> <!-- red 600 -->
+ <color name="biometric_dialog_face_checkmark">#34A853</color> <!-- green 500 -->
<!-- SFPS colors -->
<color name="sfps_chevron_fill">@color/material_dynamic_primary90</color>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index df57f2a..1b2362d 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1793,9 +1793,9 @@
the lockscreen -->
<dimen name="communal_right_edge_swipe_region_width">40dp</dimen>
<!-- Height of area at top of communal hub where swipes should open the notification shade -->
- <dimen name="communal_top_edge_swipe_region_height">68dp</dimen>
+ <dimen name="communal_top_edge_swipe_region_height">64dp</dimen>
<!-- Height of area at bottom of communal hub where swipes should open the bouncer -->
- <dimen name="communal_bottom_edge_swipe_region_height">68dp</dimen>
+ <dimen name="communal_bottom_edge_swipe_region_height">140dp</dimen>
<dimen name="drag_and_drop_icon_size">70dp</dimen>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/dagger/qualifiers/UiBackground.java b/packages/SystemUI/shared/src/com/android/systemui/dagger/qualifiers/UiBackground.java
index bf2237a..3d37468 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/dagger/qualifiers/UiBackground.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/dagger/qualifiers/UiBackground.java
@@ -23,7 +23,6 @@
import javax.inject.Qualifier;
-
/**
* An annotation for injecting instances related to UI operations off the main-thread.
*/
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/condition/Condition.java b/packages/SystemUI/shared/src/com/android/systemui/shared/condition/Condition.java
index 9bead94..670feeb 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/condition/Condition.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/condition/Condition.java
@@ -24,6 +24,8 @@
import androidx.lifecycle.LifecycleEventObserver;
import androidx.lifecycle.LifecycleOwner;
+import kotlinx.coroutines.CoroutineScope;
+
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.ref.WeakReference;
@@ -33,8 +35,6 @@
import java.util.Iterator;
import java.util.List;
-import kotlinx.coroutines.CoroutineScope;
-
/**
* Base class for a condition that needs to be fulfilled in order for {@link Monitor} to inform
* its callbacks.
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
index dcc1440..94b6fd4 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
@@ -156,9 +156,11 @@
oneway void animateNavBarLongPress(boolean isTouchDown, boolean shrink, long durationMs) = 54;
/**
- * Set the override value for home button long press duration in ms and slop multiplier.
+ * Set the override value for home button long press duration in ms and slop multiplier and
+ * haptic.
*/
- oneway void setOverrideHomeButtonLongPress(long duration, float slopMultiplier) = 55;
+ oneway void setOverrideHomeButtonLongPress(long duration, float slopMultiplier, boolean haptic)
+ = 55;
// Next id = 56
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/RotationButtonController.java b/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/RotationButtonController.java
index 400f652..87b473f 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/RotationButtonController.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/RotationButtonController.java
@@ -17,7 +17,6 @@
package com.android.systemui.shared.rotation;
import static android.content.pm.PackageManager.FEATURE_PC;
-import static android.os.Process.THREAD_PRIORITY_BACKGROUND;
import static android.view.Display.DEFAULT_DISPLAY;
import static com.android.internal.view.RotationPolicy.NATURAL_ROTATION;
@@ -38,8 +37,6 @@
import android.graphics.drawable.AnimatedVectorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Handler;
-import android.os.HandlerExecutor;
-import android.os.HandlerThread;
import android.os.Looper;
import android.os.RemoteException;
import android.os.SystemProperties;
diff --git a/packages/SystemUI/src/com/android/keyguard/CarrierTextManager.java b/packages/SystemUI/src/com/android/keyguard/CarrierTextManager.java
index 5647b0b..3f34df7 100644
--- a/packages/SystemUI/src/com/android/keyguard/CarrierTextManager.java
+++ b/packages/SystemUI/src/com/android/keyguard/CarrierTextManager.java
@@ -49,6 +49,8 @@
import com.android.systemui.telephony.TelephonyListenerManager;
import com.android.systemui.util.kotlin.JavaAdapter;
+import kotlinx.coroutines.Job;
+
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
@@ -58,8 +60,6 @@
import javax.inject.Inject;
-import kotlinx.coroutines.Job;
-
/**
* Controller that generates text including the carrier names and/or the status of all the SIM
* interfaces in the device. Through a callback, the updates can be retrieved either as a list or
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
index fb331b6..4af366c 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
@@ -49,7 +49,6 @@
import javax.inject.Inject;
-
@SysUISingleton
public class KeyguardDisplayManager {
protected static final String TAG = "KeyguardDisplayManager";
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java
index 75d925d..db14a0f 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java
@@ -47,7 +47,6 @@
import javax.inject.Inject;
-
/** Controller for a {@link KeyguardSecurityView}. */
public abstract class KeyguardInputViewController<T extends KeyguardInputView>
extends ViewController<T> implements KeyguardSecurityView {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
index 26e91b6..641c5dd 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
@@ -58,7 +58,6 @@
import com.android.systemui.res.R;
import com.android.systemui.statusbar.policy.DevicePostureController;
-
/**
* Displays an alphanumeric (latin-1) key entry for the user to enter
* an unlock password
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipperController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipperController.java
index ec2999f..120045f 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipperController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipperController.java
@@ -30,8 +30,8 @@
import com.android.keyguard.KeyguardInputViewController.Factory;
import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
import com.android.keyguard.dagger.KeyguardBouncerScope;
-import com.android.systemui.res.R;
import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.res.R;
import com.android.systemui.util.ViewController;
import java.util.ArrayList;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java
index 151ca8a..d2221c2 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java
@@ -24,7 +24,6 @@
import com.android.systemui.res.R;
-
/**
* Displays a PIN pad for entering a PUK (Pin Unlock Kode) provided by a carrier.
*/
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUserSwitcherPopupMenu.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUserSwitcherPopupMenu.java
index f746459..6b8673e 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUserSwitcherPopupMenu.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUserSwitcherPopupMenu.java
@@ -25,8 +25,8 @@
import android.widget.ListPopupWindow;
import android.widget.ListView;
-import com.android.systemui.res.R;
import com.android.systemui.plugins.FalsingManager;
+import com.android.systemui.res.R;
/**
* Custom user-switcher for use on the bouncer.
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java
index afeb0f8..9513c8e 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java
@@ -27,7 +27,6 @@
import com.android.systemui.shade.domain.interactor.ShadeLockscreenInteractor;
import com.android.systemui.statusbar.phone.BiometricUnlockController;
import com.android.systemui.statusbar.phone.CentralSurfaces;
-import com.android.systemui.statusbar.phone.KeyguardBypassController;
/**
* Interface to control Keyguard View. It should be implemented by KeyguardViewManagers, which
diff --git a/packages/SystemUI/src/com/android/keyguard/LegacyLockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LegacyLockIconViewController.java
index cf2675b..a9fd340 100644
--- a/packages/SystemUI/src/com/android/keyguard/LegacyLockIconViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/LegacyLockIconViewController.java
@@ -83,14 +83,14 @@
import dagger.Lazy;
+import kotlinx.coroutines.ExperimentalCoroutinesApi;
+
import java.io.PrintWriter;
import java.util.Objects;
import java.util.function.Consumer;
import javax.inject.Inject;
-import kotlinx.coroutines.ExperimentalCoroutinesApi;
-
/**
* Controls when to show the LockIcon affordance (lock/unlocked icon or circle) on lock screen.
*
diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerComponent.java b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerComponent.java
index b57c2b5..786965a 100644
--- a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerComponent.java
+++ b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerComponent.java
@@ -19,8 +19,8 @@
import android.view.ViewGroup;
import com.android.keyguard.KeyguardSecurityContainerController;
-import com.android.systemui.dagger.qualifiers.RootView;
import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor;
+import com.android.systemui.dagger.qualifiers.RootView;
import dagger.BindsInstance;
import dagger.Subcomponent;
diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusBarViewModule.java b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusBarViewModule.java
index 37600da..8fb5204 100644
--- a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusBarViewModule.java
+++ b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusBarViewModule.java
@@ -17,8 +17,8 @@
package com.android.keyguard.dagger;
import com.android.keyguard.CarrierText;
-import com.android.systemui.res.R;
import com.android.systemui.battery.BatteryMeterView;
+import com.android.systemui.res.R;
import com.android.systemui.statusbar.phone.KeyguardStatusBarView;
import com.android.systemui.statusbar.phone.StatusBarLocation;
import com.android.systemui.statusbar.phone.userswitcher.StatusBarUserSwitcherContainer;
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index 33f14d4..a42f4c2d 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -64,7 +64,6 @@
import javax.inject.Inject;
import javax.inject.Named;
-
/**
* Class to handle ugly dependencies throughout sysui until we determine the
* long-term dependency injection solution.
diff --git a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
index 086713f..57c1fd0 100644
--- a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
@@ -36,10 +36,9 @@
import androidx.core.animation.AnimatorListenerAdapter;
import androidx.core.animation.ObjectAnimator;
-import com.android.systemui.res.R;
-
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.jank.InteractionJankMonitor;
+import com.android.systemui.res.R;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.ExpandableView;
import com.android.systemui.statusbar.policy.ScrollAdapter;
diff --git a/packages/SystemUI/src/com/android/systemui/ForegroundServicesDialog.java b/packages/SystemUI/src/com/android/systemui/ForegroundServicesDialog.java
index ab431d0..09526a3 100644
--- a/packages/SystemUI/src/com/android/systemui/ForegroundServicesDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/ForegroundServicesDialog.java
@@ -37,11 +37,11 @@
import android.widget.ListView;
import android.widget.TextView;
-import com.android.systemui.res.R;
import com.android.internal.app.AlertActivity;
import com.android.internal.app.AlertController;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto;
+import com.android.systemui.res.R;
import java.util.ArrayList;
diff --git a/packages/SystemUI/src/com/android/systemui/GuestResumeSessionReceiver.java b/packages/SystemUI/src/com/android/systemui/GuestResumeSessionReceiver.java
index 0f5f869..13b6672 100644
--- a/packages/SystemUI/src/com/android/systemui/GuestResumeSessionReceiver.java
+++ b/packages/SystemUI/src/com/android/systemui/GuestResumeSessionReceiver.java
@@ -24,7 +24,6 @@
import androidx.annotation.NonNull;
-import com.android.systemui.res.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.UiEventLogger;
import com.android.systemui.GuestResetOrExitSessionReceiver.ResetSessionDialogFactory;
@@ -32,6 +31,7 @@
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.qs.QSUserSwitcherEvent;
+import com.android.systemui.res.R;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.phone.SystemUIDialog;
import com.android.systemui.statusbar.policy.UserSwitcherController;
diff --git a/packages/SystemUI/src/com/android/systemui/GuestSessionNotification.java b/packages/SystemUI/src/com/android/systemui/GuestSessionNotification.java
index 161cb43..06d126c 100644
--- a/packages/SystemUI/src/com/android/systemui/GuestSessionNotification.java
+++ b/packages/SystemUI/src/com/android/systemui/GuestSessionNotification.java
@@ -26,8 +26,8 @@
import android.os.UserHandle;
import android.provider.Settings;
-import com.android.systemui.res.R;
import com.android.internal.messages.nano.SystemMessageProto;
+import com.android.systemui.res.R;
import com.android.systemui.util.NotificationChannels;
import javax.inject.Inject;
diff --git a/packages/SystemUI/src/com/android/systemui/HardwareBgDrawable.java b/packages/SystemUI/src/com/android/systemui/HardwareBgDrawable.java
index 0643d02..d3bda8e 100644
--- a/packages/SystemUI/src/com/android/systemui/HardwareBgDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/HardwareBgDrawable.java
@@ -23,8 +23,8 @@
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
-import com.android.systemui.res.R;
import com.android.settingslib.Utils;
+import com.android.systemui.res.R;
public class HardwareBgDrawable extends LayerDrawable {
diff --git a/packages/SystemUI/src/com/android/systemui/PluginInflateContainer.java b/packages/SystemUI/src/com/android/systemui/PluginInflateContainer.java
index b9e412c..302ea39 100644
--- a/packages/SystemUI/src/com/android/systemui/PluginInflateContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/PluginInflateContainer.java
@@ -20,10 +20,10 @@
import android.util.Log;
import android.view.View;
-import com.android.systemui.res.R;
import com.android.systemui.plugins.PluginListener;
import com.android.systemui.plugins.PluginManager;
import com.android.systemui.plugins.ViewProvider;
+import com.android.systemui.res.R;
/**
* Define an interface or abstract class as follows that includes the
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityTargetAdapter.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityTargetAdapter.java
index 83ad3c2..5160309 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityTargetAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityTargetAdapter.java
@@ -29,8 +29,8 @@
import com.android.internal.accessibility.common.ShortcutConstants.AccessibilityFragmentType;
import com.android.internal.accessibility.dialog.AccessibilityTarget;
-import com.android.systemui.res.R;
import com.android.systemui.accessibility.floatingmenu.AccessibilityTargetAdapter.ViewHolder;
+import com.android.systemui.res.R;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuEduTooltipView.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuEduTooltipView.java
index 1ff9eb4..c4274ea 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuEduTooltipView.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuEduTooltipView.java
@@ -41,8 +41,8 @@
import androidx.annotation.NonNull;
import com.android.settingslib.Utils;
-import com.android.systemui.res.R;
import com.android.systemui.recents.TriangleShape;
+import com.android.systemui.res.R;
/**
* The tooltip view shows the information about the operation of the anchor view {@link MenuView}
diff --git a/packages/SystemUI/src/com/android/systemui/ambient/touch/dagger/InputSessionModule.java b/packages/SystemUI/src/com/android/systemui/ambient/touch/dagger/InputSessionModule.java
index 99dbdee..5875ffc 100644
--- a/packages/SystemUI/src/com/android/systemui/ambient/touch/dagger/InputSessionModule.java
+++ b/packages/SystemUI/src/com/android/systemui/ambient/touch/dagger/InputSessionModule.java
@@ -28,7 +28,6 @@
import javax.inject.Named;
-
/**
* Module for providing dependencies to {@link com.android.systemui.dreams.touch.InputSession}.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistModule.java b/packages/SystemUI/src/com/android/systemui/assist/AssistModule.java
index f9138b6..b0eddea 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistModule.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistModule.java
@@ -26,11 +26,11 @@
import com.android.internal.app.AssistUtils;
import com.android.systemui.dagger.SysUISingleton;
-import javax.inject.Named;
-
import dagger.Module;
import dagger.Provides;
+import javax.inject.Named;
+
/** Module for dagger injections related to the Assistant. */
@Module
public abstract class AssistModule {
diff --git a/packages/SystemUI/src/com/android/systemui/assist/PhoneStateMonitor.java b/packages/SystemUI/src/com/android/systemui/assist/PhoneStateMonitor.java
index dfff00b..e425f29 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/PhoneStateMonitor.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/PhoneStateMonitor.java
@@ -38,14 +38,14 @@
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.phone.CentralSurfaces;
+import dagger.Lazy;
+
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import javax.inject.Inject;
-import dagger.Lazy;
-
/** Class to monitor and report the state of the phone. */
@SysUISingleton
public final class PhoneStateMonitor {
diff --git a/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterViewController.java b/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterViewController.java
index 5b840b5..4f13e6f 100644
--- a/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterViewController.java
@@ -30,14 +30,14 @@
import androidx.annotation.NonNull;
-import com.android.systemui.res.R;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
+import com.android.systemui.res.R;
import com.android.systemui.settings.UserTracker;
-import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.statusbar.phone.StatusBarLocation;
+import com.android.systemui.statusbar.phone.ui.StatusBarIconController;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.tuner.TunerService;
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
index fd0e7fc..ea5c5da 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
@@ -87,6 +87,8 @@
import com.android.systemui.statusbar.VibratorHelper;
import com.android.systemui.util.concurrency.DelayableExecutor;
+import kotlinx.coroutines.CoroutineScope;
+
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -96,8 +98,6 @@
import javax.inject.Provider;
-import kotlinx.coroutines.CoroutineScope;
-
/**
* Top level container/controller for the BiometricPrompt UI.
*
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index b25c3da..fb718d3 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -110,6 +110,9 @@
import kotlin.Unit;
+import kotlinx.coroutines.CoroutineScope;
+import kotlinx.coroutines.ExperimentalCoroutinesApi;
+
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashSet;
@@ -118,9 +121,6 @@
import javax.inject.Inject;
-import kotlinx.coroutines.CoroutineScope;
-import kotlinx.coroutines.ExperimentalCoroutinesApi;
-
/**
* Shows and hides the under-display fingerprint sensor (UDFPS) overlay, handles UDFPS touch events,
* and toggles the UDFPS display mode.
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinder.kt
index 245817e..4bdbfa2 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinder.kt
@@ -122,11 +122,9 @@
val overlayViewModel =
SideFpsOverlayViewModel(
applicationContext,
- biometricStatusInteractor.get(),
deviceEntrySideFpsOverlayInteractor.get(),
displayStateInteractor.get(),
sfpsSensorInteractor.get(),
- sideFpsProgressBarViewModel.get()
)
bind(overlayView!!, overlayViewModel, fpsUnlockTracker.get(), windowManager.get())
overlayView!!.visibility = View.INVISIBLE
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModel.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModel.kt
index 412d0c3..19ea007 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModel.kt
@@ -30,7 +30,6 @@
import com.airbnb.lottie.model.KeyPath
import com.android.systemui.Flags.constraintBp
import com.android.systemui.biometrics.Utils
-import com.android.systemui.biometrics.domain.interactor.BiometricStatusInteractor
import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractor
import com.android.systemui.biometrics.domain.interactor.SideFpsSensorInteractor
import com.android.systemui.biometrics.domain.model.SideFpsSensorLocation
@@ -38,7 +37,6 @@
import com.android.systemui.biometrics.shared.model.LottieCallback
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.domain.interactor.DeviceEntrySideFpsOverlayInteractor
-import com.android.systemui.keyguard.ui.viewmodel.SideFpsProgressBarViewModel
import com.android.systemui.res.R
import com.android.systemui.util.kotlin.sample
import javax.inject.Inject
@@ -54,11 +52,9 @@
@Inject
constructor(
@Application private val applicationContext: Context,
- biometricStatusInteractor: BiometricStatusInteractor,
deviceEntrySideFpsOverlayInteractor: DeviceEntrySideFpsOverlayInteractor,
displayStateInteractor: DisplayStateInteractor,
sfpsSensorInteractor: SideFpsSensorInteractor,
- sideFpsProgressBarViewModel: SideFpsProgressBarViewModel
) {
/** Contains properties of the side fingerprint sensor indicator */
data class OverlayViewProperties(
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt
index cb458ef..45e39ca 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt
@@ -34,7 +34,7 @@
import com.android.systemui.deviceentry.domain.interactor.DeviceEntryFaceAuthInteractor
import com.android.systemui.log.SessionTracker
import com.android.systemui.power.domain.interactor.PowerInteractor
-import com.android.systemui.scene.domain.interactor.SceneInteractor
+import com.android.systemui.scene.domain.interactor.SceneBackInteractor
import com.android.systemui.scene.shared.model.Scenes
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
@@ -59,7 +59,7 @@
private val powerInteractor: PowerInteractor,
private val uiEventLogger: UiEventLogger,
private val sessionTracker: SessionTracker,
- sceneInteractor: SceneInteractor,
+ sceneBackInteractor: SceneBackInteractor,
) {
private val _onIncorrectBouncerInput = MutableSharedFlow<Unit>()
val onIncorrectBouncerInput: SharedFlow<Unit> = _onIncorrectBouncerInput
@@ -95,7 +95,9 @@
/** The scene to show when bouncer is dismissed. */
val dismissDestination: Flow<SceneKey> =
- sceneInteractor.previousScene(Scenes.Bouncer).map { it ?: Scenes.Lockscreen }
+ sceneBackInteractor.backScene
+ .filter { it != Scenes.Bouncer }
+ .map { it ?: Scenes.Lockscreen }
/** Notifies that the user has places down a pointer, not necessarily dragging just yet. */
fun onDown() {
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/ProximityClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/ProximityClassifier.java
index 0123857..82fe2f1 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/ProximityClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/ProximityClassifier.java
@@ -33,7 +33,6 @@
import javax.inject.Inject;
-
/**
* False touch if proximity sensor is covered for more than a certain percentage of the gesture.
*
diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java
index bfc80a7..bd0e729 100644
--- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java
@@ -18,7 +18,6 @@
import static android.content.Intent.ACTION_CLOSE_SYSTEM_DIALOGS;
-
import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.CLIPBOARD_OVERLAY_SHOW_ACTIONS;
import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_ACTION_SHOWN;
import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_ACTION_TAPPED;
diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/dagger/ClipboardOverlayModule.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/dagger/ClipboardOverlayModule.java
index 0fd34bd..ff9fba4 100644
--- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/dagger/ClipboardOverlayModule.java
+++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/dagger/ClipboardOverlayModule.java
@@ -25,18 +25,18 @@
import android.view.Display;
import android.view.LayoutInflater;
-import com.android.systemui.res.R;
import com.android.systemui.clipboardoverlay.ClipboardOverlayView;
+import com.android.systemui.res.R;
import com.android.systemui.settings.DisplayTracker;
+import dagger.Module;
+import dagger.Provides;
+
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import javax.inject.Qualifier;
-import dagger.Module;
-import dagger.Provides;
-
/** Module for {@link com.android.systemui.clipboardoverlay}. */
@Module
public interface ClipboardOverlayModule {
diff --git a/packages/SystemUI/src/com/android/systemui/communal/dagger/CommunalModule.kt b/packages/SystemUI/src/com/android/systemui/communal/dagger/CommunalModule.kt
index 7fa091a..2406cc6 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/dagger/CommunalModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/dagger/CommunalModule.kt
@@ -76,7 +76,12 @@
val config =
SceneContainerConfig(
sceneKeys = listOf(CommunalScenes.Blank, CommunalScenes.Communal),
- initialSceneKey = CommunalScenes.Blank
+ initialSceneKey = CommunalScenes.Blank,
+ navigationDistances =
+ mapOf(
+ CommunalScenes.Blank to 0,
+ CommunalScenes.Communal to 1,
+ ),
)
return SceneDataSourceDelegator(applicationScope, config)
}
diff --git a/packages/SystemUI/src/com/android/systemui/complication/ComplicationLayoutEngine.java b/packages/SystemUI/src/com/android/systemui/complication/ComplicationLayoutEngine.java
index f7b6b0f..15ec4d4 100644
--- a/packages/SystemUI/src/com/android/systemui/complication/ComplicationLayoutEngine.java
+++ b/packages/SystemUI/src/com/android/systemui/complication/ComplicationLayoutEngine.java
@@ -40,10 +40,10 @@
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.constraintlayout.widget.Constraints;
-import com.android.systemui.res.R;
import com.android.systemui.complication.ComplicationLayoutParams.Direction;
import com.android.systemui.complication.ComplicationLayoutParams.Position;
import com.android.systemui.complication.dagger.ComplicationModule;
+import com.android.systemui.res.R;
import com.android.systemui.statusbar.CrossFadeHelper;
import com.android.systemui.touch.TouchInsetManager;
diff --git a/packages/SystemUI/src/com/android/systemui/complication/dagger/ComplicationHostViewModule.java b/packages/SystemUI/src/com/android/systemui/complication/dagger/ComplicationHostViewModule.java
index 712213a..9dd48ea 100644
--- a/packages/SystemUI/src/com/android/systemui/complication/dagger/ComplicationHostViewModule.java
+++ b/packages/SystemUI/src/com/android/systemui/complication/dagger/ComplicationHostViewModule.java
@@ -22,8 +22,8 @@
import androidx.constraintlayout.widget.ConstraintLayout;
import com.android.internal.util.Preconditions;
-import com.android.systemui.res.R;
import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.res.R;
import dagger.Module;
import dagger.Provides;
diff --git a/packages/SystemUI/src/com/android/systemui/complication/dagger/ComplicationModule.java b/packages/SystemUI/src/com/android/systemui/complication/dagger/ComplicationModule.java
index 57841af..9475372 100644
--- a/packages/SystemUI/src/com/android/systemui/complication/dagger/ComplicationModule.java
+++ b/packages/SystemUI/src/com/android/systemui/complication/dagger/ComplicationModule.java
@@ -34,6 +34,7 @@
import javax.inject.Named;
import javax.inject.Scope;
+
/**
* Module for housing components related to rendering complications.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/complication/dagger/DreamHomeControlsComplicationComponent.java b/packages/SystemUI/src/com/android/systemui/complication/dagger/DreamHomeControlsComplicationComponent.java
index b6dcfcb..63ac77d 100644
--- a/packages/SystemUI/src/com/android/systemui/complication/dagger/DreamHomeControlsComplicationComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/complication/dagger/DreamHomeControlsComplicationComponent.java
@@ -34,7 +34,6 @@
import dagger.Provides;
import dagger.Subcomponent;
-
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
diff --git a/packages/SystemUI/src/com/android/systemui/complication/dagger/DreamMediaEntryComplicationComponent.java b/packages/SystemUI/src/com/android/systemui/complication/dagger/DreamMediaEntryComplicationComponent.java
index c0a292c..b680393 100644
--- a/packages/SystemUI/src/com/android/systemui/complication/dagger/DreamMediaEntryComplicationComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/complication/dagger/DreamMediaEntryComplicationComponent.java
@@ -21,8 +21,8 @@
import android.view.LayoutInflater;
import android.view.View;
-import com.android.systemui.res.R;
import com.android.systemui.complication.DreamMediaEntryComplication;
+import com.android.systemui.res.R;
import dagger.Module;
import dagger.Provides;
diff --git a/packages/SystemUI/src/com/android/systemui/complication/dagger/RegisteredComplicationsModule.java b/packages/SystemUI/src/com/android/systemui/complication/dagger/RegisteredComplicationsModule.java
index 92fdb1e..6f1b098 100644
--- a/packages/SystemUI/src/com/android/systemui/complication/dagger/RegisteredComplicationsModule.java
+++ b/packages/SystemUI/src/com/android/systemui/complication/dagger/RegisteredComplicationsModule.java
@@ -19,12 +19,12 @@
import android.content.res.Resources;
import android.view.ViewGroup;
-import com.android.systemui.res.R;
import com.android.systemui.complication.ComplicationLayoutParams;
import com.android.systemui.dagger.SystemUIBinder;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
+import com.android.systemui.res.R;
import dagger.Module;
import dagger.Provides;
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/NightDisplayListenerModule.java b/packages/SystemUI/src/com/android/systemui/dagger/NightDisplayListenerModule.java
index 7091105..42fca7d 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/NightDisplayListenerModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/NightDisplayListenerModule.java
@@ -23,11 +23,11 @@
import com.android.systemui.dagger.qualifiers.Background;
-import javax.inject.Inject;
-
import dagger.Module;
import dagger.Provides;
+import javax.inject.Inject;
+
/**
* Module for providing a {@link NightDisplayListener}.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceGlobalRootComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceGlobalRootComponent.java
index be93c9f..c663db0 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceGlobalRootComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceGlobalRootComponent.java
@@ -16,10 +16,10 @@
package com.android.systemui.dagger;
-import javax.inject.Singleton;
-
import dagger.Component;
+import javax.inject.Singleton;
+
/**
* Root component for Dagger injection used in AOSP.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/InstrumentationTest.java b/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/InstrumentationTest.java
index a803a39..9430445 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/InstrumentationTest.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/InstrumentationTest.java
@@ -23,7 +23,6 @@
import javax.inject.Qualifier;
-
/**
* An annotation for injecting whether or not we are running in a test environment.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/TestHarness.java b/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/TestHarness.java
index f68ab18..35c7b76 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/TestHarness.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/TestHarness.java
@@ -23,7 +23,6 @@
import javax.inject.Qualifier;
-
/**
* An annotation for injecting whether or not we are running in a test environment.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/data/repository/DeviceEntryFaceAuthRepository.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/data/repository/DeviceEntryFaceAuthRepository.kt
index e418641..f1ab4d1 100644
--- a/packages/SystemUI/src/com/android/systemui/deviceentry/data/repository/DeviceEntryFaceAuthRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/deviceentry/data/repository/DeviceEntryFaceAuthRepository.kt
@@ -250,7 +250,10 @@
listOf(
*gatingConditionsForAuthAndDetect(),
Pair(isLockedOut.isFalse(), "isNotInLockOutState"),
- Pair(trustRepository.isCurrentUserTrusted.isFalse(), "currentUserIsNotTrusted"),
+ Pair(
+ keyguardRepository.isKeyguardDismissible.isFalse(),
+ "keyguardIsNotDismissible"
+ ),
Pair(
biometricSettingsRepository.isFaceAuthCurrentlyAllowed,
"isFaceAuthCurrentlyAllowed"
@@ -273,7 +276,7 @@
Pair(
biometricSettingsRepository.isFaceAuthCurrentlyAllowed
.isFalse()
- .or(trustRepository.isCurrentUserTrusted),
+ .or(keyguardRepository.isKeyguardDismissible),
"faceAuthIsNotCurrentlyAllowedOrCurrentUserIsTrusted"
),
// We don't want to run face detect if fingerprint can be used to unlock the
diff --git a/packages/SystemUI/src/com/android/systemui/doze/AlwaysOnDisplayPolicy.java b/packages/SystemUI/src/com/android/systemui/doze/AlwaysOnDisplayPolicy.java
index 8e542b5..e182d0b 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/AlwaysOnDisplayPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/AlwaysOnDisplayPolicy.java
@@ -28,8 +28,8 @@
import android.util.KeyValueListParser;
import android.util.Log;
-import com.android.systemui.res.R;
import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.res.R;
import javax.inject.Inject;
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSuppressor.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSuppressor.java
index de0bdd3..2cafe99 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeSuppressor.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSuppressor.java
@@ -26,12 +26,12 @@
import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.phone.BiometricUnlockController;
+import dagger.Lazy;
+
import java.io.PrintWriter;
import javax.inject.Inject;
-import dagger.Lazy;
-
/**
* Handles suppressing doze on:
* 1. INITIALIZED, don't allow dozing at all when:
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
index 0c2709e..8c0a73c 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
@@ -48,13 +48,13 @@
import com.android.systemui.statusbar.BlurUtils;
import com.android.systemui.util.ViewController;
+import kotlinx.coroutines.CoroutineDispatcher;
+
import java.util.Arrays;
import javax.inject.Inject;
import javax.inject.Named;
-import kotlinx.coroutines.CoroutineDispatcher;
-
/**
* View controller for {@link DreamOverlayContainerView}.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
index a9ef531..c618e92 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
@@ -359,7 +359,9 @@
return;
}
- setLifecycleStateLocked(Lifecycle.State.RESUMED);
+ // Set lifecycle to resumed only if there's nothing covering the dream, ex. shade, bouncer,
+ // or hub. These updates can come in before onStartDream runs.
+ updateLifecycleStateLocked();
mStateController.setOverlayActive(true);
final ComponentName dreamComponent = getDreamComponent();
mStateController.setLowLightActive(
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/conditions/AssistantAttentionCondition.java b/packages/SystemUI/src/com/android/systemui/dreams/conditions/AssistantAttentionCondition.java
index 4dd97d5..d81949d 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/conditions/AssistantAttentionCondition.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/conditions/AssistantAttentionCondition.java
@@ -21,10 +21,10 @@
import com.android.systemui.dagger.qualifiers.Application;
import com.android.systemui.shared.condition.Condition;
-import javax.inject.Inject;
-
import kotlinx.coroutines.CoroutineScope;
+import javax.inject.Inject;
+
/**
* {@link AssistantAttentionCondition} provides a signal when assistant has the user's attention.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/conditions/DreamCondition.java b/packages/SystemUI/src/com/android/systemui/dreams/conditions/DreamCondition.java
index 99688be..c7fe1e1 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/conditions/DreamCondition.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/conditions/DreamCondition.java
@@ -22,10 +22,10 @@
import com.android.systemui.dagger.qualifiers.Application;
import com.android.systemui.shared.condition.Condition;
-import javax.inject.Inject;
-
import kotlinx.coroutines.CoroutineScope;
+import javax.inject.Inject;
+
/**
* {@link DreamCondition} provides a signal when a dream begins and ends.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsClassicDebug.java b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsClassicDebug.java
index 72b0891..7d11d32 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsClassicDebug.java
+++ b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsClassicDebug.java
@@ -25,6 +25,7 @@
import static com.android.systemui.flags.FlagManager.EXTRA_VALUE;
import static com.android.systemui.flags.FlagsCommonModule.ALL_FLAGS;
import static com.android.systemui.shared.Flags.exampleSharedFlag;
+
import static java.util.Objects.requireNonNull;
import android.content.BroadcastReceiver;
diff --git a/packages/SystemUI/src/com/android/systemui/flags/FlagDependencies.kt b/packages/SystemUI/src/com/android/systemui/flags/FlagDependencies.kt
index 8b1f8d3..67c5564 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/FlagDependencies.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/FlagDependencies.kt
@@ -25,7 +25,6 @@
import com.android.systemui.Flags.FLAG_COMMUNAL_HUB
import com.android.systemui.Flags.communalHub
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.flags.Flags.MIGRATE_KEYGUARD_STATUS_BAR_VIEW
import com.android.systemui.keyguard.KeyguardBottomAreaRefactor
import com.android.systemui.keyguard.MigrateClocksToBlueprint
import com.android.systemui.keyguard.shared.ComposeLockscreen
@@ -53,7 +52,6 @@
// SceneContainer dependencies
SceneContainerFlag.getFlagDependencies().forEach { (alpha, beta) -> alpha dependsOn beta }
- SceneContainerFlag.getMainAconfigFlag() dependsOn MIGRATE_KEYGUARD_STATUS_BAR_VIEW
// ComposeLockscreen dependencies
ComposeLockscreen.token dependsOn KeyguardBottomAreaRefactor.token
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index 04f1ad2..2e49919 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -178,16 +178,11 @@
/** Flag meant to guard the talkback fix for the KeyguardIndicationTextView */
// TODO(b/286563884): Tracking bug
- @JvmField val KEYGUARD_TALKBACK_FIX = releasedFlag("keyguard_talkback_fix")
+ @JvmField val KEYGUARD_TALKBACK_FIX = unreleasedFlag("keyguard_talkback_fix")
// TODO(b/287268101): Tracking bug.
@JvmField val TRANSIT_CLOCK = releasedFlag("lockscreen_custom_transit_clock")
- /** Migrate the status bar view on keyguard from notification panel to keyguard root view. */
- // TODO(b/299115332): Tracking Bug.
- @JvmField val MIGRATE_KEYGUARD_STATUS_BAR_VIEW =
- unreleasedFlag("migrate_keyguard_status_bar_view")
-
/** Enables preview loading animation in the wallpaper picker. */
// TODO(b/274443705): Tracking Bug
@JvmField
diff --git a/packages/SystemUI/src/com/android/systemui/haptics/qs/QSLongPressEffect.kt b/packages/SystemUI/src/com/android/systemui/haptics/qs/QSLongPressEffect.kt
index f1a8faf..db2ec8f 100644
--- a/packages/SystemUI/src/com/android/systemui/haptics/qs/QSLongPressEffect.kt
+++ b/packages/SystemUI/src/com/android/systemui/haptics/qs/QSLongPressEffect.kt
@@ -16,20 +16,14 @@
package com.android.systemui.haptics.qs
-import android.animation.ValueAnimator
import android.os.VibrationEffect
import android.view.View
-import android.view.animation.AccelerateDecelerateInterpolator
import androidx.annotation.VisibleForTesting
-import androidx.core.animation.doOnCancel
-import androidx.core.animation.doOnEnd
-import androidx.core.animation.doOnStart
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.statusbar.VibratorHelper
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.combine
/**
@@ -50,17 +44,14 @@
keyguardInteractor: KeyguardInteractor,
) {
- private var effectDuration = 0
+ var effectDuration = 0
+ private set
/** Current state */
- private var _state = MutableStateFlow(State.IDLE)
- val state = _state.asStateFlow()
+ var state = State.IDLE
+ private set
- /** Flows for view control and action */
- private val _effectProgress = MutableStateFlow<Float?>(null)
- val effectProgress = _effectProgress.asStateFlow()
-
- // Actions to perform
+ /** Flow for view control and action */
private val _postedActionType = MutableStateFlow<ActionType?>(null)
val actionType: Flow<ActionType?> =
combine(
@@ -85,29 +76,23 @@
private val snapEffect = LongPressHapticBuilder.createSnapEffect()
- private var effectAnimator: ValueAnimator? = null
-
val hasInitialized: Boolean
- get() = longPressHint != null && effectAnimator != null
+ get() = longPressHint != null
@VisibleForTesting
- fun setState(state: State) {
- _state.value = state
+ fun setState(newState: State) {
+ state = newState
}
- private fun reverse() {
- effectAnimator?.let {
- val pausedProgress = it.animatedFraction
- val effect =
- LongPressHapticBuilder.createReversedEffect(
- pausedProgress,
- durations?.get(0) ?: 0,
- effectDuration,
- )
- vibratorHelper?.cancel()
- vibrate(effect)
- it.reverse()
- }
+ fun playReverseHaptics(pausedProgress: Float) {
+ val effect =
+ LongPressHapticBuilder.createReversedEffect(
+ pausedProgress,
+ durations?.get(0) ?: 0,
+ effectDuration,
+ )
+ vibratorHelper?.cancel()
+ vibrate(effect)
}
private fun vibrate(effect: VibrationEffect?) {
@@ -117,23 +102,23 @@
}
fun handleActionDown() {
- when (_state.value) {
+ when (state) {
State.IDLE -> {
setState(State.TIMEOUT_WAIT)
}
- State.RUNNING_BACKWARDS -> effectAnimator?.cancel()
+ State.RUNNING_BACKWARDS -> _postedActionType.value = ActionType.CANCEL_ANIMATOR
else -> {}
}
}
fun handleActionUp() {
- when (_state.value) {
+ when (state) {
State.TIMEOUT_WAIT -> {
_postedActionType.value = ActionType.CLICK
setState(State.IDLE)
}
State.RUNNING_FORWARD -> {
- reverse()
+ _postedActionType.value = ActionType.REVERSE_ANIMATOR
setState(State.RUNNING_BACKWARDS)
}
else -> {}
@@ -141,44 +126,42 @@
}
fun handleActionCancel() {
- when (_state.value) {
+ when (state) {
State.TIMEOUT_WAIT -> {
setState(State.IDLE)
}
State.RUNNING_FORWARD -> {
- reverse()
+ _postedActionType.value = ActionType.REVERSE_ANIMATOR
setState(State.RUNNING_BACKWARDS)
}
else -> {}
}
}
- private fun handleAnimationStart() {
+ fun handleAnimationStart() {
vibrate(longPressHint)
setState(State.RUNNING_FORWARD)
}
/** This function is called both when an animator completes or gets cancelled */
- private fun handleAnimationComplete() {
- if (_state.value == State.RUNNING_FORWARD) {
+ fun handleAnimationComplete() {
+ if (state == State.RUNNING_FORWARD) {
vibrate(snapEffect)
_postedActionType.value = ActionType.LONG_PRESS
- _effectProgress.value = null
}
- if (_state.value != State.TIMEOUT_WAIT) {
+ if (state != State.TIMEOUT_WAIT) {
// This will happen if the animator did not finish by being cancelled
setState(State.IDLE)
}
}
- private fun handleAnimationCancel() {
- _effectProgress.value = null
+ fun handleAnimationCancel() {
setState(State.TIMEOUT_WAIT)
}
fun handleTimeoutComplete() {
- if (_state.value == State.TIMEOUT_WAIT && effectAnimator?.isRunning == false) {
- effectAnimator?.start()
+ if (state == State.TIMEOUT_WAIT) {
+ _postedActionType.value = ActionType.START_ANIMATOR
}
}
@@ -186,18 +169,6 @@
_postedActionType.value = null
}
- /** Reset the effect by going back to a default [IDLE] state */
- fun resetEffect() {
- if (effectAnimator?.isRunning == true) {
- effectAnimator?.cancel()
- }
- longPressHint = null
- effectAnimator = null
- _effectProgress.value = null
- _postedActionType.value = null
- setState(State.IDLE)
- }
-
/**
* Reset the effect with a new effect duration.
*
@@ -205,27 +176,21 @@
* @return true if the effect initialized correctly
*/
fun initializeEffect(duration: Int): Boolean {
- // The effect can't reset if it is running
+ // The effect can't initialize with a negative duration
if (duration <= 0) return false
- resetEffect()
- effectDuration = duration
- effectAnimator =
- ValueAnimator.ofFloat(0f, 1f).apply {
- this.duration = effectDuration.toLong()
- interpolator = AccelerateDecelerateInterpolator()
+ // There is no need to re-initialize if the duration has not changed
+ if (duration == effectDuration) return true
- doOnStart { handleAnimationStart() }
- addUpdateListener { _effectProgress.value = animatedValue as Float }
- doOnEnd { handleAnimationComplete() }
- doOnCancel { handleAnimationCancel() }
- }
+ effectDuration = duration
longPressHint =
LongPressHapticBuilder.createLongPressHint(
durations?.get(0) ?: LongPressHapticBuilder.INVALID_DURATION,
durations?.get(1) ?: LongPressHapticBuilder.INVALID_DURATION,
effectDuration
)
+ _postedActionType.value = ActionType.INITIALIZE_ANIMATOR
+ setState(State.IDLE)
return true
}
@@ -241,5 +206,9 @@
CLICK,
LONG_PRESS,
RESET_AND_LONG_PRESS,
+ START_ANIMATOR,
+ REVERSE_ANIMATOR,
+ CANCEL_ANIMATOR,
+ INITIALIZE_ANIMATOR,
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/haptics/qs/QSLongPressEffectViewBinder.kt b/packages/SystemUI/src/com/android/systemui/haptics/qs/QSLongPressEffectViewBinder.kt
index dd7a285..c591af2 100644
--- a/packages/SystemUI/src/com/android/systemui/haptics/qs/QSLongPressEffectViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/haptics/qs/QSLongPressEffectViewBinder.kt
@@ -16,9 +16,14 @@
package com.android.systemui.haptics.qs
+import android.animation.ValueAnimator
import android.annotation.SuppressLint
import android.view.MotionEvent
import android.view.ViewConfiguration
+import android.view.animation.AccelerateDecelerateInterpolator
+import androidx.core.animation.doOnCancel
+import androidx.core.animation.doOnEnd
+import androidx.core.animation.doOnStart
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
import com.android.app.tracing.coroutines.launch
@@ -40,32 +45,63 @@
return tile.repeatWhenAttached {
repeatOnLifecycle(Lifecycle.State.CREATED) {
- // Progress of the effect
- launch({ "${tileSpec ?: "unknownTileSpec"}#LongPressEffect#progress" }) {
- qsLongPressEffect.effectProgress.collect { progress ->
- progress?.let {
- if (it == 0f) {
- tile.bringToFront()
- } else {
- tile.updateLongPressEffectProperties(it)
- }
- }
- }
- }
-
// Action to perform
launch({ "${tileSpec ?: "unknownTileSpec"}#LongPressEffect#action" }) {
+ var effectAnimator: ValueAnimator? = null
+
qsLongPressEffect.actionType.collect { action ->
action?.let {
when (it) {
- QSLongPressEffect.ActionType.CLICK -> tile.performClick()
- QSLongPressEffect.ActionType.LONG_PRESS -> tile.performLongClick()
+ QSLongPressEffect.ActionType.CLICK -> {
+ tile.performClick()
+ qsLongPressEffect.clearActionType()
+ }
+ QSLongPressEffect.ActionType.LONG_PRESS -> {
+ tile.performLongClick()
+ qsLongPressEffect.clearActionType()
+ }
QSLongPressEffect.ActionType.RESET_AND_LONG_PRESS -> {
tile.resetLongPressEffectProperties()
tile.performLongClick()
+ qsLongPressEffect.clearActionType()
+ }
+ QSLongPressEffect.ActionType.START_ANIMATOR -> {
+ if (effectAnimator?.isRunning == false) {
+ effectAnimator?.start()
+ }
+ }
+ QSLongPressEffect.ActionType.REVERSE_ANIMATOR -> {
+ effectAnimator?.let {
+ val pausedProgress = it.animatedFraction
+ qsLongPressEffect.playReverseHaptics(pausedProgress)
+ it.reverse()
+ }
+ }
+ QSLongPressEffect.ActionType.CANCEL_ANIMATOR -> {
+ tile.resetLongPressEffectProperties()
+ effectAnimator?.cancel()
+ }
+ QSLongPressEffect.ActionType.INITIALIZE_ANIMATOR -> {
+ effectAnimator =
+ ValueAnimator.ofFloat(0f, 1f).apply {
+ this.duration =
+ qsLongPressEffect.effectDuration.toLong()
+ interpolator = AccelerateDecelerateInterpolator()
+
+ doOnStart { qsLongPressEffect.handleAnimationStart() }
+ addUpdateListener {
+ val value = animatedValue as Float
+ if (value == 0f) {
+ tile.bringToFront()
+ } else {
+ tile.updateLongPressEffectProperties(value)
+ }
+ }
+ doOnEnd { qsLongPressEffect.handleAnimationComplete() }
+ doOnCancel { qsLongPressEffect.handleAnimationCancel() }
+ }
}
}
- qsLongPressEffect.clearActionType()
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/KeyboardUI.java b/packages/SystemUI/src/com/android/systemui/keyboard/KeyboardUI.java
index 17e3ca6..1fac7f1 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/KeyboardUI.java
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/KeyboardUI.java
@@ -50,8 +50,8 @@
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
import com.android.systemui.CoreStartable;
-import com.android.systemui.res.R;
import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.res.R;
import com.android.systemui.statusbar.phone.SystemUIDialog;
import com.android.systemui.util.settings.SecureSettings;
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
index a5d7e04..ae163ea 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
@@ -89,14 +89,14 @@
import com.android.wm.shell.shared.TransitionUtil;
import com.android.wm.shell.transition.Transitions;
+import kotlinx.coroutines.CoroutineScope;
+
import java.util.ArrayList;
import java.util.Map;
import java.util.WeakHashMap;
import javax.inject.Inject;
-import kotlinx.coroutines.CoroutineScope;
-
public class KeyguardService extends Service {
static final String TAG = "KeyguardService";
static final String PERMISSION = android.Manifest.permission.CONTROL_KEYGUARD;
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
index 0d40511..dbaa297 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
@@ -48,10 +48,10 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
-import com.android.systemui.res.R;
import com.android.systemui.SystemUIAppComponentFactoryBase;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.res.R;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.statusbar.StatusBarState;
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/WakefulnessLifecycle.java b/packages/SystemUI/src/com/android/systemui/keyguard/WakefulnessLifecycle.java
index 4f02f75..39144b5 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/WakefulnessLifecycle.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/WakefulnessLifecycle.java
@@ -30,10 +30,10 @@
import androidx.annotation.Nullable;
import com.android.systemui.Dumpable;
-import com.android.systemui.res.R;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.power.domain.interactor.PowerInteractor;
+import com.android.systemui.res.R;
import com.android.systemui.util.time.SystemClock;
import java.io.PrintWriter;
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivity.java b/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivity.java
index 09875a5..2c5bacb 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivity.java
@@ -37,8 +37,8 @@
import android.window.OnBackInvokedDispatcher;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.res.R;
import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.res.R;
import javax.inject.Inject;
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
index 7879ab6..4e6cfcc 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
@@ -90,11 +90,11 @@
import dagger.multibindings.ClassKey;
import dagger.multibindings.IntoMap;
-import java.util.concurrent.Executor;
-
import kotlinx.coroutines.CoroutineDispatcher;
import kotlinx.coroutines.ExperimentalCoroutinesApi;
+import java.util.concurrent.Executor;
+
/**
* Dagger Module providing keyguard.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultStatusBarSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultStatusBarSection.kt
index f713d5e..9b5fae3 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultStatusBarSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultStatusBarSection.kt
@@ -27,10 +27,9 @@
import androidx.constraintlayout.widget.ConstraintSet.START
import androidx.constraintlayout.widget.ConstraintSet.TOP
import com.android.keyguard.dagger.KeyguardStatusBarViewComponent
-import com.android.systemui.res.R
-import com.android.systemui.flags.FeatureFlags
-import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.shared.model.KeyguardSection
+import com.android.systemui.res.R
+import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.shade.NotificationPanelView
import com.android.systemui.shade.ShadeViewStateProvider
import com.android.systemui.statusbar.phone.KeyguardStatusBarView
@@ -42,7 +41,6 @@
@Inject
constructor(
private val context: Context,
- private val featureFlags: FeatureFlags,
private val notificationPanelView: NotificationPanelView,
private val keyguardStatusBarViewComponentFactory: KeyguardStatusBarViewComponent.Factory,
) : KeyguardSection() {
@@ -50,7 +48,7 @@
private val statusBarViewId = R.id.keyguard_header
override fun addViews(constraintLayout: ConstraintLayout) {
- if (!featureFlags.isEnabled(Flags.MIGRATE_KEYGUARD_STATUS_BAR_VIEW)) {
+ if (!SceneContainerFlag.isEnabled) {
return
}
@@ -67,7 +65,7 @@
}
override fun bindData(constraintLayout: ConstraintLayout) {
- if (!featureFlags.isEnabled(Flags.MIGRATE_KEYGUARD_STATUS_BAR_VIEW)) {
+ if (!SceneContainerFlag.isEnabled) {
return
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModel.kt
index 644bea0..5b83a10 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModel.kt
@@ -27,6 +27,7 @@
import com.android.systemui.keyguard.domain.interactor.BurnInInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
+import com.android.systemui.keyguard.shared.ComposeLockscreen
import com.android.systemui.keyguard.shared.model.BurnInModel
import com.android.systemui.keyguard.shared.model.ClockSize
import com.android.systemui.keyguard.ui.StateToValue
@@ -126,32 +127,41 @@
val useScaleOnly =
useAltAod && keyguardClockViewModel.clockSize.value == ClockSize.LARGE
- if (useScaleOnly) {
- BurnInModel(
- translationX = 0,
- translationY = 0,
- scale = MathUtils.lerp(burnIn.scale, 1f, 1f - interpolated),
- )
- } else {
- // Ensure the desired translation doesn't encroach on the top inset
- val burnInY = MathUtils.lerp(0, burnIn.translationY, interpolated).toInt()
- val translationY =
- if (MigrateClocksToBlueprint.isEnabled) {
- max(params.topInset - params.minViewY, burnInY)
- } else {
- max(params.topInset, params.minViewY + burnInY) - params.minViewY
- }
+ val burnInY = MathUtils.lerp(0, burnIn.translationY, interpolated).toInt()
+ val translationY =
+ if (MigrateClocksToBlueprint.isEnabled) {
+ max(params.topInset - params.minViewY, burnInY)
+ } else {
+ max(params.topInset, params.minViewY + burnInY) - params.minViewY
+ }
+ if (ComposeLockscreen.isEnabled) {
BurnInModel(
translationX = MathUtils.lerp(0, burnIn.translationX, interpolated).toInt(),
translationY = translationY,
- scale =
- MathUtils.lerp(
- /* start= */ burnIn.scale,
- /* stop= */ 1f,
- /* amount= */ 1f - interpolated,
- ),
- scaleClockOnly = true,
+ scale = MathUtils.lerp(burnIn.scale, 1f, 1f - interpolated),
+ scaleClockOnly = !useScaleOnly,
)
+ } else {
+ if (useScaleOnly) {
+ BurnInModel(
+ translationX = 0,
+ translationY = 0,
+ scale = MathUtils.lerp(burnIn.scale, 1f, 1f - interpolated),
+ )
+ } else {
+ // Ensure the desired translation doesn't encroach on the top inset
+ BurnInModel(
+ translationX = MathUtils.lerp(0, burnIn.translationX, interpolated).toInt(),
+ translationY = translationY,
+ scale =
+ MathUtils.lerp(
+ /* start= */ burnIn.scale,
+ /* stop= */ 1f,
+ /* amount= */ 1f - interpolated,
+ ),
+ scaleClockOnly = true,
+ )
+ }
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/logcat/LogAccessDialogActivity.java b/packages/SystemUI/src/com/android/systemui/logcat/LogAccessDialogActivity.java
index d01917a..fd526b9 100644
--- a/packages/SystemUI/src/com/android/systemui/logcat/LogAccessDialogActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/logcat/LogAccessDialogActivity.java
@@ -45,7 +45,6 @@
import com.android.internal.app.ILogAccessDialogCallback;
import com.android.systemui.res.R;
-
/**
* Dialog responsible for obtaining user consent per-use log access
*/
diff --git a/packages/SystemUI/src/com/android/systemui/media/systemsounds/HomeSoundEffectController.java b/packages/SystemUI/src/com/android/systemui/media/systemsounds/HomeSoundEffectController.java
index 9de2b4f..74af4ee 100644
--- a/packages/SystemUI/src/com/android/systemui/media/systemsounds/HomeSoundEffectController.java
+++ b/packages/SystemUI/src/com/android/systemui/media/systemsounds/HomeSoundEffectController.java
@@ -26,8 +26,8 @@
import android.util.Slog;
import com.android.systemui.CoreStartable;
-import com.android.systemui.res.R;
import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.res.R;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.shared.system.TaskStackChangeListeners;
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
index 43c73c4..1a2ae8a 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
@@ -243,6 +243,7 @@
private Optional<Long> mHomeButtonLongPressDurationMs;
private Optional<Long> mOverrideHomeButtonLongPressDurationMs = Optional.empty();
private Optional<Float> mOverrideHomeButtonLongPressSlopMultiplier = Optional.empty();
+ private boolean mHomeButtonLongPressHapticEnabled = true;
/** @see android.view.WindowInsetsController#setSystemBarsAppearance(int, int) */
private @Appearance int mAppearance;
@@ -410,13 +411,15 @@
}
@Override
- public void setOverrideHomeButtonLongPress(long duration, float slopMultiplier) {
- Log.d(TAG, "setOverrideHomeButtonLongPress receives: " + duration + "; "
- + slopMultiplier);
+ public void setOverrideHomeButtonLongPress(long duration, float slopMultiplier,
+ boolean haptic) {
+ Log.d(TAG, "setOverrideHomeButtonLongPress receives: " + duration + ";"
+ + slopMultiplier + ";" + haptic);
mOverrideHomeButtonLongPressDurationMs = Optional.of(duration)
.filter(value -> value > 0);
mOverrideHomeButtonLongPressSlopMultiplier = Optional.of(slopMultiplier)
.filter(value -> value > 0);
+ mHomeButtonLongPressHapticEnabled = haptic;
mOverrideHomeButtonLongPressDurationMs.ifPresent(aLong
-> Log.d(TAG, "Use duration override: " + aLong));
mOverrideHomeButtonLongPressSlopMultiplier.ifPresent(aFloat
@@ -463,9 +466,11 @@
private final Runnable mEnableLayoutTransitions = () -> mView.setLayoutTransitionsEnabled(true);
private final Runnable mOnVariableDurationHomeLongClick = () -> {
if (onHomeLongClick(mView.getHomeButton().getCurrentView())) {
- mView.getHomeButton().getCurrentView().performHapticFeedback(
- HapticFeedbackConstants.LONG_PRESS,
- HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
+ if (mHomeButtonLongPressHapticEnabled) {
+ mView.getHomeButton().getCurrentView().performHapticFeedback(
+ HapticFeedbackConstants.LONG_PRESS,
+ HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
+ }
}
};
@@ -1042,7 +1047,8 @@
mView.getHomeButton().setOnLongClickListener(null);
} else {
mView.getHomeButton().getCurrentView().setLongClickable(true);
- mView.getHomeButton().getCurrentView().setHapticFeedbackEnabled(true);
+ mView.getHomeButton().getCurrentView().setHapticFeedbackEnabled(
+ mHomeButtonLongPressHapticEnabled);
mView.getHomeButton().setOnLongClickListener(this::onHomeLongClick);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarComponent.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarComponent.java
index 1d792af..4f713d6 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarComponent.java
@@ -25,14 +25,14 @@
import com.android.systemui.dagger.qualifiers.DisplayId;
+import dagger.BindsInstance;
+import dagger.Subcomponent;
+
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import javax.inject.Scope;
-import dagger.BindsInstance;
-import dagger.Subcomponent;
-
/**
* Subcomponent for a NavigationBar.
*
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarControllerImpl.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarControllerImpl.java
index 12f2703..b177b0b 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarControllerImpl.java
@@ -74,7 +74,6 @@
import javax.inject.Inject;
-
@SysUISingleton
public class NavigationBarControllerImpl implements
ConfigurationController.ConfigurationListener,
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarInflaterView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarInflaterView.java
index c1d98c9..2ae0709 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarInflaterView.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarInflaterView.java
@@ -36,12 +36,12 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.Dependency;
-import com.android.systemui.res.R;
import com.android.systemui.navigationbar.buttons.ButtonDispatcher;
import com.android.systemui.navigationbar.buttons.KeyButtonView;
import com.android.systemui.navigationbar.buttons.ReverseLinearLayout;
import com.android.systemui.navigationbar.buttons.ReverseLinearLayout.ReverseRelativeLayout;
import com.android.systemui.recents.OverviewProxyService;
+import com.android.systemui.res.R;
import com.android.systemui.shared.system.QuickStepContract;
import java.io.PrintWriter;
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarModule.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarModule.java
index 3ef5094..aab4fea 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarModule.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarModule.java
@@ -21,10 +21,10 @@
import android.view.View;
import android.view.WindowManager;
-import com.android.systemui.res.R;
import com.android.systemui.dagger.qualifiers.DisplayId;
import com.android.systemui.navigationbar.NavigationBarComponent.NavigationBarScope;
import com.android.systemui.navigationbar.gestural.EdgeBackGestureHandler;
+import com.android.systemui.res.R;
import dagger.Module;
import dagger.Provides;
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarTransitions.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarTransitions.java
index 3e34318..201e586 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarTransitions.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarTransitions.java
@@ -24,9 +24,9 @@
import android.util.SparseArray;
import android.view.View;
-import com.android.systemui.res.R;
import com.android.systemui.navigationbar.NavigationBarComponent.NavigationBarScope;
import com.android.systemui.navigationbar.buttons.ButtonDispatcher;
+import com.android.systemui.res.R;
import com.android.systemui.settings.DisplayTracker;
import com.android.systemui.statusbar.phone.BarTransitions;
import com.android.systemui.statusbar.phone.LightBarTransitionsController;
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/ScreenPinningNotify.java b/packages/SystemUI/src/com/android/systemui/navigationbar/ScreenPinningNotify.java
index 939c096..1e40dd9 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/ScreenPinningNotify.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/ScreenPinningNotify.java
@@ -21,8 +21,8 @@
import android.util.Slog;
import android.widget.Toast;
-import com.android.systemui.res.R;
import com.android.systemui.SysUIToast;
+import com.android.systemui.res.R;
/**
* Helper to manage showing/hiding a image to notify them that they are entering or exiting screen
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/DeadZone.java b/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/DeadZone.java
index bd3a0c1..3268306 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/DeadZone.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/DeadZone.java
@@ -26,9 +26,9 @@
import android.view.Surface;
import com.android.systemui.Dependency;
-import com.android.systemui.res.R;
import com.android.systemui.navigationbar.NavigationBarController;
import com.android.systemui.navigationbar.NavigationBarView;
+import com.android.systemui.res.R;
import javax.inject.Inject;
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
index b50ee57..933065b 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
@@ -516,9 +516,9 @@
SystemUiDeviceConfigFlags.BACK_GESTURE_SLOP_MULTIPLIER, 0.75f);
mTouchSlop = mViewConfiguration.getScaledTouchSlop() * backGestureSlop;
mBackSwipeLinearThreshold = res.getDimension(
- R.dimen.navigation_edge_action_progress_threshold);
+ com.android.internal.R.dimen.navigation_edge_action_progress_threshold);
mNonLinearFactor = getDimenFloat(res,
- R.dimen.back_progress_non_linear_factor);
+ com.android.internal.R.dimen.back_progress_non_linear_factor);
updateBackAnimationThresholds();
}
@@ -1094,15 +1094,12 @@
return;
} else if (dx > dy && dx > mTouchSlop) {
if (mAllowGesture) {
- mThresholdCrossed = true;
- // Capture inputs
- mInputMonitor.pilferPointers();
if (mBackAnimation != null) {
- mBackAnimation.onPilferPointers();
- // Notify FalsingManager that an intentional gesture has occurred.
- mFalsingManager.isFalseTouch(BACK_GESTURE);
+ mBackAnimation.onThresholdCrossed();
+ } else {
+ pilferPointers();
}
- mInputEventReceiver.setBatchingEnabled(true);
+ mThresholdCrossed = true;
} else {
logGesture(SysUiStatsLog.BACK_GESTURE__TYPE__INCOMPLETE_FAR_FROM_EDGE);
}
@@ -1118,6 +1115,14 @@
}
}
+ private void pilferPointers() {
+ // Capture inputs
+ mInputMonitor.pilferPointers();
+ // Notify FalsingManager that an intentional gesture has occurred.
+ mFalsingManager.isFalseTouch(BACK_GESTURE);
+ mInputEventReceiver.setBatchingEnabled(true);
+ }
+
private boolean isButtonPressFromTrackpad(MotionEvent ev) {
// We don't allow back for button press from the trackpad, and yet we do with a mouse.
int sources = InputManager.getInstance().getInputDevice(ev.getDeviceId()).getSources();
@@ -1266,6 +1271,9 @@
public void setBackAnimation(BackAnimation backAnimation) {
mBackAnimation = backAnimation;
+ mBackAnimation.setPilferPointerCallback(() -> {
+ pilferPointers();
+ });
updateBackAnimationThresholds();
if (mLightBarControllerProvider.get() != null) {
mBackAnimation.setStatusBarCustomizer((appearance) -> {
diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java
index 188e867..d23d3f6 100644
--- a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java
+++ b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java
@@ -55,9 +55,9 @@
import com.android.internal.util.ArrayUtils;
import com.android.internal.widget.MessagingMessage;
import com.android.settingslib.utils.ThreadUtils;
-import com.android.systemui.res.R;
import com.android.systemui.people.widget.PeopleSpaceWidgetManager;
import com.android.systemui.people.widget.PeopleTileKey;
+import com.android.systemui.res.R;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import java.text.SimpleDateFormat;
diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleTileViewHelper.java b/packages/SystemUI/src/com/android/systemui/people/PeopleTileViewHelper.java
index ef72967..9b57b40 100644
--- a/packages/SystemUI/src/com/android/systemui/people/PeopleTileViewHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/people/PeopleTileViewHelper.java
@@ -74,11 +74,11 @@
import androidx.core.math.MathUtils;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.res.R;
import com.android.systemui.people.data.model.PeopleTileModel;
import com.android.systemui.people.widget.LaunchConversationActivity;
import com.android.systemui.people.widget.PeopleSpaceWidgetProvider;
import com.android.systemui.people.widget.PeopleTileKey;
+import com.android.systemui.res.R;
import java.io.IOException;
import java.text.NumberFormat;
diff --git a/packages/SystemUI/src/com/android/systemui/plugins/PluginDependencyProvider.java b/packages/SystemUI/src/com/android/systemui/plugins/PluginDependencyProvider.java
index e6575d5a..c65742c 100644
--- a/packages/SystemUI/src/com/android/systemui/plugins/PluginDependencyProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/plugins/PluginDependencyProvider.java
@@ -19,11 +19,11 @@
import com.android.systemui.Dependency;
import com.android.systemui.plugins.PluginDependency.DependencyProvider;
+import dagger.Lazy;
+
import javax.inject.Inject;
import javax.inject.Singleton;
-import dagger.Lazy;
-
/**
*/
@Singleton
diff --git a/packages/SystemUI/src/com/android/systemui/plugins/PluginsModule.java b/packages/SystemUI/src/com/android/systemui/plugins/PluginsModule.java
index 1f66b84..dbdec6b 100644
--- a/packages/SystemUI/src/com/android/systemui/plugins/PluginsModule.java
+++ b/packages/SystemUI/src/com/android/systemui/plugins/PluginsModule.java
@@ -21,9 +21,9 @@
import android.content.pm.PackageManager;
import android.os.Build;
-import com.android.systemui.res.R;
import com.android.systemui.dagger.PluginModule;
import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.res.R;
import com.android.systemui.shared.plugins.PluginActionManager;
import com.android.systemui.shared.plugins.PluginEnabler;
import com.android.systemui.shared.plugins.PluginInstance;
@@ -33,6 +33,10 @@
import com.android.systemui.util.concurrency.GlobalConcurrencyModule;
import com.android.systemui.util.concurrency.ThreadFactory;
+import dagger.Binds;
+import dagger.Module;
+import dagger.Provides;
+
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.Executor;
@@ -40,10 +44,6 @@
import javax.inject.Named;
import javax.inject.Singleton;
-import dagger.Binds;
-import dagger.Module;
-import dagger.Provides;
-
/**
* Dagger Module for code related to plugins.
*
diff --git a/packages/SystemUI/src/com/android/systemui/power/dagger/PowerModule.java b/packages/SystemUI/src/com/android/systemui/power/dagger/PowerModule.java
index 8dd0ea0..b889f8e 100644
--- a/packages/SystemUI/src/com/android/systemui/power/dagger/PowerModule.java
+++ b/packages/SystemUI/src/com/android/systemui/power/dagger/PowerModule.java
@@ -30,7 +30,6 @@
import dagger.multibindings.IntoMap;
import dagger.multibindings.IntoSet;
-
/** Dagger Module for code in the power package. */
@Module(
includes = {
diff --git a/packages/SystemUI/src/com/android/systemui/process/condition/SystemProcessCondition.java b/packages/SystemUI/src/com/android/systemui/process/condition/SystemProcessCondition.java
index b6a5ad6..694b525 100644
--- a/packages/SystemUI/src/com/android/systemui/process/condition/SystemProcessCondition.java
+++ b/packages/SystemUI/src/com/android/systemui/process/condition/SystemProcessCondition.java
@@ -20,10 +20,10 @@
import com.android.systemui.process.ProcessWrapper;
import com.android.systemui.shared.condition.Condition;
-import javax.inject.Inject;
-
import kotlinx.coroutines.CoroutineScope;
+import javax.inject.Inject;
+
/**
* {@link SystemProcessCondition} checks to make sure the current process is being ran by the
* System User.
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java
index ffbd06f..d715f42 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java
@@ -23,10 +23,10 @@
import android.widget.TextView;
import android.widget.Toast;
-import com.android.systemui.res.R;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.qs.dagger.QSScope;
+import com.android.systemui.res.R;
import com.android.systemui.retail.domain.interactor.RetailModeInteractor;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.util.ViewController;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSScrollLayout.java b/packages/SystemUI/src/com/android/systemui/qs/QSScrollLayout.java
index 77a5ce3..dc83201 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSScrollLayout.java
@@ -26,9 +26,9 @@
import androidx.core.widget.NestedScrollView;
-import com.android.systemui.res.R;
import com.android.systemui.qs.touch.OverScroll;
import com.android.systemui.qs.touch.SwipeDetector;
+import com.android.systemui.res.R;
/**
* Quick setting scroll view containing the brightness slider and the QS tiles.
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
index 6c32ed3..168be40 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
@@ -25,8 +25,8 @@
import com.android.internal.logging.UiEventLogger;
import com.android.systemui.FontSizeUtils;
-import com.android.systemui.res.R;
import com.android.systemui.plugins.qs.QSTile;
+import com.android.systemui.res.R;
/**
* Version of QSPanel that only shows N Quick Tiles in the QS Header.
diff --git a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFlagsModule.java b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFlagsModule.java
index a1b617f..7cb950b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFlagsModule.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFlagsModule.java
@@ -24,11 +24,11 @@
import com.android.systemui.flags.Flags;
import com.android.systemui.util.settings.GlobalSettings;
-import javax.inject.Named;
-
import dagger.Module;
import dagger.Provides;
+import javax.inject.Named;
+
@Module
public interface QSFlagsModule {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/QSTileServiceWrapper.java b/packages/SystemUI/src/com/android/systemui/qs/external/QSTileServiceWrapper.java
index 83b6f0d..c302ee2 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/QSTileServiceWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/QSTileServiceWrapper.java
@@ -21,7 +21,6 @@
import androidx.annotation.NonNull;
-
public class QSTileServiceWrapper {
private static final String TAG = "IQSTileServiceWrapper";
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java
index 3ee4a1b..f8bf0a6 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java
@@ -31,11 +31,9 @@
import androidx.annotation.VisibleForTesting;
-import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.qs.external.TileLifecycleManager.TileChangeListener;
import com.android.systemui.qs.pipeline.data.repository.CustomTileAddedRepository;
import com.android.systemui.settings.UserTracker;
-import com.android.systemui.util.concurrency.DelayableExecutor;
import java.util.List;
import java.util.Objects;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
index c3744df..8278c79 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
@@ -46,7 +46,7 @@
import com.android.systemui.qs.pipeline.domain.interactor.PanelInteractor;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.phone.StatusBarIconController;
+import com.android.systemui.statusbar.phone.ui.StatusBarIconController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.concurrency.DelayableExecutor;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
index bdcbac0..b929c43 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
@@ -25,13 +25,13 @@
import com.android.systemui.qs.QSHost;
import com.android.systemui.qs.external.CustomTile;
+import dagger.Lazy;
+
import java.util.Map;
import javax.inject.Inject;
import javax.inject.Provider;
-import dagger.Lazy;
-
/**
* A factory that creates Quick Settings tiles based on a tileSpec
*
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CameraToggleTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CameraToggleTile.java
index 736f035..6502a42 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CameraToggleTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CameraToggleTile.java
@@ -31,7 +31,6 @@
import androidx.annotation.NonNull;
import com.android.internal.logging.MetricsLogger;
-import com.android.systemui.res.R;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.ActivityStarter;
@@ -40,6 +39,7 @@
import com.android.systemui.qs.QSHost;
import com.android.systemui.qs.QsEventLogger;
import com.android.systemui.qs.logging.QSLogger;
+import com.android.systemui.res.R;
import com.android.systemui.statusbar.policy.IndividualSensorPrivacyController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataUsageDetailView.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataUsageDetailView.java
index c15289f..1a8530f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataUsageDetailView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataUsageDetailView.java
@@ -28,8 +28,8 @@
import com.android.settingslib.Utils;
import com.android.settingslib.net.DataUsageController;
import com.android.systemui.FontSizeUtils;
-import com.android.systemui.res.R;
import com.android.systemui.qs.DataUsageGraph;
+import com.android.systemui.res.R;
import java.text.DecimalFormat;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
index 9fab51f..f022981 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
@@ -29,7 +29,6 @@
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.systemui.res.R;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.ActivityStarter;
@@ -40,6 +39,7 @@
import com.android.systemui.qs.QsEventLogger;
import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.qs.tileimpl.QSTileImpl;
+import com.android.systemui.res.R;
import com.android.systemui.statusbar.policy.FlashlightController;
import javax.inject.Inject;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
index 9ee417e..4d0404d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
@@ -33,7 +33,6 @@
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settingslib.wifi.WifiEnterpriseRestrictionUtils;
-import com.android.systemui.res.R;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.ActivityStarter;
@@ -44,6 +43,7 @@
import com.android.systemui.qs.QsEventLogger;
import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.qs.tileimpl.QSTileImpl;
+import com.android.systemui.res.R;
import com.android.systemui.statusbar.policy.DataSaverController;
import com.android.systemui.statusbar.policy.HotspotController;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java
index 24b2d8a..0f260e3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java
@@ -41,7 +41,6 @@
import com.android.settingslib.graph.SignalDrawable;
import com.android.settingslib.mobile.TelephonyIcons;
import com.android.settingslib.net.DataUsageController;
-import com.android.systemui.res.R;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.ActivityStarter;
@@ -53,6 +52,7 @@
import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.qs.tileimpl.QSTileImpl;
import com.android.systemui.qs.tiles.dialog.InternetDialogManager;
+import com.android.systemui.res.R;
import com.android.systemui.statusbar.connectivity.AccessPointController;
import com.android.systemui.statusbar.connectivity.IconState;
import com.android.systemui.statusbar.connectivity.MobileDataIndicators;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
index 9ddcf295..b3f0d8b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
@@ -29,7 +29,6 @@
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.systemui.res.R;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.ActivityStarter;
@@ -41,6 +40,7 @@
import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.qs.pipeline.domain.interactor.PanelInteractor;
import com.android.systemui.qs.tileimpl.QSTileImpl;
+import com.android.systemui.res.R;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.LocationController;
import com.android.systemui.statusbar.policy.LocationController.LocationChangeCallback;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/MicrophoneToggleTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/MicrophoneToggleTile.java
index 92338cb..36f3dc7 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/MicrophoneToggleTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/MicrophoneToggleTile.java
@@ -31,7 +31,6 @@
import androidx.annotation.NonNull;
import com.android.internal.logging.MetricsLogger;
-import com.android.systemui.res.R;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.ActivityStarter;
@@ -40,6 +39,7 @@
import com.android.systemui.qs.QSHost;
import com.android.systemui.qs.QsEventLogger;
import com.android.systemui.qs.logging.QSLogger;
+import com.android.systemui.res.R;
import com.android.systemui.statusbar.policy.IndividualSensorPrivacyController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java
index a239c28..d650f73 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java
@@ -34,7 +34,6 @@
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.systemui.res.R;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
@@ -46,6 +45,7 @@
import com.android.systemui.qs.QsEventLogger;
import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.qs.tileimpl.QSTileImpl;
+import com.android.systemui.res.R;
import javax.inject.Inject;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java
index 7e0fa07..a1ea46d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java
@@ -36,7 +36,6 @@
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.systemui.res.R;
import com.android.systemui.dagger.NightDisplayListenerModule;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
@@ -48,6 +47,7 @@
import com.android.systemui.qs.QsEventLogger;
import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.qs.tileimpl.QSTileImpl;
+import com.android.systemui.res.R;
import com.android.systemui.statusbar.policy.LocationController;
import java.text.DateFormat;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ReduceBrightColorsTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ReduceBrightColorsTile.java
index b9d902a..76ada10 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ReduceBrightColorsTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ReduceBrightColorsTile.java
@@ -30,7 +30,6 @@
import com.android.internal.R;
import com.android.internal.logging.MetricsLogger;
-import com.android.systemui.res.R.drawable;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.ActivityStarter;
@@ -42,6 +41,7 @@
import com.android.systemui.qs.ReduceBrightColorsController;
import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.qs.tileimpl.QSTileImpl;
+import com.android.systemui.res.R.drawable;
import javax.inject.Inject;
import javax.inject.Named;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java
index 300cc56..d92873ada 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java
@@ -31,7 +31,6 @@
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto;
-import com.android.systemui.res.R;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.ActivityStarter;
@@ -42,6 +41,7 @@
import com.android.systemui.qs.QsEventLogger;
import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.qs.tileimpl.QSTileImpl;
+import com.android.systemui.res.R;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.LocationController;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java
index 7a9384a..abc4812 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java
@@ -32,7 +32,6 @@
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.systemui.res.R;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.ActivityStarter;
@@ -43,6 +42,7 @@
import com.android.systemui.qs.QsEventLogger;
import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.qs.tileimpl.QSTileImpl;
+import com.android.systemui.res.R;
import com.android.systemui.statusbar.phone.ManagedProfileController;
import javax.inject.Inject;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModel.kt
index c1986fa..22146ce 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModel.kt
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+@file:OptIn(ExperimentalCoroutinesApi::class)
+
package com.android.systemui.qs.ui.viewmodel
import androidx.lifecycle.LifecycleOwner
@@ -30,7 +32,7 @@
import com.android.systemui.qs.FooterActionsController
import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsViewModel
import com.android.systemui.qs.ui.adapter.QSSceneAdapter
-import com.android.systemui.scene.domain.interactor.SceneInteractor
+import com.android.systemui.scene.domain.interactor.SceneBackInteractor
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.settings.brightness.ui.viewModel.BrightnessMirrorViewModel
import com.android.systemui.shade.ui.viewmodel.ShadeHeaderViewModel
@@ -42,6 +44,8 @@
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.filter
+import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
/** Models UI state and handles user input for the quick settings scene. */
@@ -57,21 +61,30 @@
val notifications: NotificationsPlaceholderViewModel,
private val footerActionsViewModelFactory: FooterActionsViewModel.Factory,
private val footerActionsController: FooterActionsController,
- sceneInteractor: SceneInteractor,
+ sceneBackInteractor: SceneBackInteractor,
) {
- @OptIn(ExperimentalCoroutinesApi::class)
+ private val backScene: StateFlow<SceneKey> =
+ sceneBackInteractor.backScene
+ .filter { it != Scenes.QuickSettings }
+ .map { it ?: Scenes.Shade }
+ .stateIn(
+ scope = applicationScope,
+ started = SharingStarted.WhileSubscribed(),
+ initialValue = Scenes.Shade,
+ )
+
val destinationScenes: StateFlow<Map<UserAction, UserActionResult>> =
combine(
deviceEntryInteractor.isUnlocked,
deviceEntryInteractor.canSwipeToEnter,
qsSceneAdapter.isCustomizing,
- sceneInteractor.previousScene(ignored = Scenes.QuickSettings),
- ) { isUnlocked, canSwipeToDismiss, isCustomizing, previousScene ->
+ backScene,
+ ) { isUnlocked, canSwipeToDismiss, isCustomizing, backScene ->
destinationScenes(
isUnlocked,
canSwipeToDismiss,
isCustomizing,
- previousScene,
+ backScene,
)
}
.stateIn(
@@ -82,8 +95,7 @@
isUnlocked = deviceEntryInteractor.isUnlocked.value,
canSwipeToDismiss = deviceEntryInteractor.canSwipeToEnter.value,
isCustomizing = qsSceneAdapter.isCustomizing.value,
- previousScene = sceneInteractor
- .previousScene(ignored = Scenes.QuickSettings).value,
+ backScene = backScene.value,
),
)
@@ -91,7 +103,7 @@
isUnlocked: Boolean,
canSwipeToDismiss: Boolean?,
isCustomizing: Boolean,
- previousScene: SceneKey?
+ backScene: SceneKey?,
): Map<UserAction, UserActionResult> {
val upBottomEdge =
when {
@@ -108,13 +120,15 @@
// TODO(b/330200163) Add an Up from Bottom to be able to collapse the shade
// while customizing
} else {
- this[Back] = UserActionResult(previousScene ?: Scenes.Shade)
- this[Swipe(SwipeDirection.Up)] = UserActionResult(previousScene ?: Scenes.Shade)
- this[
+ put(Back, UserActionResult(backScene ?: Scenes.Shade))
+ put(Swipe(SwipeDirection.Up), UserActionResult(backScene ?: Scenes.Shade))
+ put(
Swipe(
fromSource = Edge.Bottom,
direction = SwipeDirection.Up,
- )] = UserActionResult(upBottomEdge)
+ ),
+ UserActionResult(upBottomEdge),
+ )
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index 1ddc094..b92e8eb 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -253,8 +253,21 @@
@Override
public void onStatusBarTrackpadEvent(MotionEvent event) {
- verifyCallerAndClearCallingIdentityPostMain("onStatusBarTrackpadEvent", () ->
- mShadeViewControllerLazy.get().handleExternalTouch(event));
+ verifyCallerAndClearCallingIdentityPostMain("onStatusBarTrackpadEvent", () -> {
+ if (SceneContainerFlag.isEnabled()) {
+ int action = event.getActionMasked();
+ if (action == ACTION_DOWN) {
+ mSceneInteractor.get().onRemoteUserInteractionStarted(
+ "trackpad swipe");
+ } else if (action == ACTION_UP) {
+ mSceneInteractor.get().changeScene(
+ Scenes.Shade, "short trackpad swipe");
+ }
+ mStatusBarWinController.getWindowRootView().dispatchTouchEvent(event);
+ } else {
+ mShadeViewControllerLazy.get().handleExternalTouch(event);
+ }
+ });
}
@Override
@@ -264,9 +277,10 @@
}
@Override
- public void setOverrideHomeButtonLongPress(long duration, float slopMultiplier) {
+ public void setOverrideHomeButtonLongPress(long duration, float slopMultiplier,
+ boolean haptic) {
verifyCallerAndClearCallingIdentityPostMain("setOverrideHomeButtonLongPress",
- () -> notifySetOverrideHomeButtonLongPress(duration, slopMultiplier));
+ () -> notifySetOverrideHomeButtonLongPress(duration, slopMultiplier, haptic));
}
@Override
@@ -956,9 +970,11 @@
}
}
- private void notifySetOverrideHomeButtonLongPress(long duration, float slopMultiplier) {
+ private void notifySetOverrideHomeButtonLongPress(long duration, float slopMultiplier,
+ boolean haptic) {
for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) {
- mConnectionCallbacks.get(i).setOverrideHomeButtonLongPress(duration, slopMultiplier);
+ mConnectionCallbacks.get(i)
+ .setOverrideHomeButtonLongPress(duration, slopMultiplier, haptic);
}
}
@@ -1119,8 +1135,9 @@
default void startAssistant(Bundle bundle) {}
default void setAssistantOverridesRequested(int[] invocationTypes) {}
default void animateNavBarLongPress(boolean isTouchDown, boolean shrink, long durationMs) {}
- /** Set override of home button long press duration and touch slop multiplier. */
- default void setOverrideHomeButtonLongPress(long override, float slopMultiplier) {}
+ /** Set override of home button long press duration, touch slop multiplier, and haptic. */
+ default void setOverrideHomeButtonLongPress(
+ long override, float slopMultiplier, boolean haptic) {}
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/scene/KeyguardlessSceneContainerFrameworkModule.kt b/packages/SystemUI/src/com/android/systemui/scene/KeyguardlessSceneContainerFrameworkModule.kt
index 8277c73..2a73b53 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/KeyguardlessSceneContainerFrameworkModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/KeyguardlessSceneContainerFrameworkModule.kt
@@ -47,6 +47,12 @@
Scenes.Shade,
),
initialSceneKey = Scenes.Gone,
+ navigationDistances =
+ mapOf(
+ Scenes.Gone to 0,
+ Scenes.Shade to 1,
+ Scenes.QuickSettings to 2,
+ ),
)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/SceneContainerFrameworkModule.kt b/packages/SystemUI/src/com/android/systemui/scene/SceneContainerFrameworkModule.kt
index 69f9443..cd1b965 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/SceneContainerFrameworkModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/SceneContainerFrameworkModule.kt
@@ -73,6 +73,15 @@
Scenes.Shade,
),
initialSceneKey = Scenes.Lockscreen,
+ navigationDistances =
+ mapOf(
+ Scenes.Gone to 0,
+ Scenes.Lockscreen to 0,
+ Scenes.Communal to 1,
+ Scenes.Shade to 2,
+ Scenes.QuickSettings to 3,
+ Scenes.Bouncer to 4,
+ ),
)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/ShadelessSceneContainerFrameworkModule.kt b/packages/SystemUI/src/com/android/systemui/scene/ShadelessSceneContainerFrameworkModule.kt
index d202c24..b918277 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/ShadelessSceneContainerFrameworkModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/ShadelessSceneContainerFrameworkModule.kt
@@ -47,6 +47,11 @@
Scenes.Bouncer,
),
initialSceneKey = Scenes.Lockscreen,
+ mapOf(
+ Scenes.Gone to 0,
+ Scenes.Lockscreen to 0,
+ Scenes.Bouncer to 1,
+ )
)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/data/repository/SceneContainerRepository.kt b/packages/SystemUI/src/com/android/systemui/scene/data/repository/SceneContainerRepository.kt
index 3082eb9..994b012 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/data/repository/SceneContainerRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/data/repository/SceneContainerRepository.kt
@@ -24,8 +24,6 @@
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.scene.shared.model.SceneContainerConfig
import com.android.systemui.scene.shared.model.SceneDataSource
-import com.android.systemui.util.kotlin.WithPrev
-import com.android.systemui.util.kotlin.pairwise
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -36,7 +34,6 @@
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
-import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
/** Source of truth for scene framework application state. */
@@ -47,32 +44,7 @@
private val config: SceneContainerConfig,
private val dataSource: SceneDataSource,
) {
- private val previousAndCurrentScene: StateFlow<WithPrev<SceneKey?, SceneKey>> =
- dataSource.currentScene
- .pairwise()
- .stateIn(
- scope = applicationScope,
- started = SharingStarted.WhileSubscribed(),
- initialValue = WithPrev(null, dataSource.currentScene.value),
- )
-
- val currentScene: StateFlow<SceneKey> =
- previousAndCurrentScene
- .map { it.newValue }
- .stateIn(
- scope = applicationScope,
- started = SharingStarted.WhileSubscribed(),
- initialValue = previousAndCurrentScene.value.newValue,
- )
-
- val previousScene: StateFlow<SceneKey?> =
- previousAndCurrentScene
- .map { it.previousValue }
- .stateIn(
- scope = applicationScope,
- started = SharingStarted.WhileSubscribed(),
- initialValue = previousAndCurrentScene.value.previousValue,
- )
+ val currentScene: StateFlow<SceneKey> = dataSource.currentScene
private val _isVisible = MutableStateFlow(true)
val isVisible: StateFlow<Boolean> = _isVisible.asStateFlow()
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneBackInteractor.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneBackInteractor.kt
new file mode 100644
index 0000000..f66d08f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneBackInteractor.kt
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.scene.domain.interactor
+
+import com.android.compose.animation.scene.SceneKey
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.scene.shared.logger.SceneLogger
+import com.android.systemui.scene.shared.model.SceneContainerConfig
+import java.util.Stack
+import javax.inject.Inject
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asStateFlow
+
+@SysUISingleton
+class SceneBackInteractor
+@Inject
+constructor(
+ private val logger: SceneLogger,
+ private val sceneContainerConfig: SceneContainerConfig,
+) {
+ private val _backScene = MutableStateFlow<SceneKey?>(null)
+ /**
+ * The scene to navigate to when the user triggers back navigation.
+ *
+ * This is meant for scene implementations to consult with when they implement their destination
+ * scene flow.
+ *
+ * Note that this flow could emit any scene from the [SceneContainerConfig] and that it's an
+ * illegal state to have scene implementation map to itself in its destination scene flow. Thus,
+ * scene implementations might wish to filter their own scene key out before using this.
+ */
+ val backScene: StateFlow<SceneKey?> = _backScene.asStateFlow()
+
+ private val backStack = Stack<SceneKey>()
+
+ fun onSceneChange(from: SceneKey, to: SceneKey) {
+ check(from != to) { "from == to, from=${from.debugName}, to=${to.debugName}" }
+ when (stackOperation(from, to)) {
+ Clear -> {
+ backStack.clear()
+ }
+ Push -> {
+ backStack.push(from)
+ }
+ Pop -> {
+ check(backStack.isNotEmpty()) { "Cannot pop ${from.debugName} when stack is empty" }
+ val popped = backStack.pop()
+ check(to == popped) {
+ "Expected to pop ${to.debugName} but instead popped ${popped.debugName}"
+ }
+ }
+ }
+
+ logger.logSceneBackStack(backStack)
+ _backScene.value = peek()
+ }
+
+ private fun stackOperation(from: SceneKey, to: SceneKey): StackOperation {
+ val fromDistance =
+ checkNotNull(sceneContainerConfig.navigationDistances[from]) {
+ "No distance mapping for scene \"${from.debugName}\"!"
+ }
+ val toDistance =
+ checkNotNull(sceneContainerConfig.navigationDistances[to]) {
+ "No distance mapping for scene \"${to.debugName}\"!"
+ }
+
+ return when {
+ toDistance == 0 -> Clear
+ toDistance > fromDistance -> Push
+ toDistance < fromDistance -> Pop
+ else ->
+ error(
+ "No mapping when from=${from.debugName} (distance=$fromDistance)," +
+ " to=${to.debugName} (distance=$toDistance)!"
+ )
+ }
+ }
+
+ private fun peek(): SceneKey? {
+ return if (backStack.isNotEmpty()) {
+ backStack.peek()
+ } else {
+ null
+ }
+ }
+
+ private sealed interface StackOperation
+ private data object Clear : StackOperation
+ private data object Push : StackOperation
+ private data object Pop : StackOperation
+}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt
index 8ced222..2ccd3b9 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt
@@ -140,33 +140,6 @@
)
/**
- * The previous scene (or `null` if the previous scene is the [ignored] scene).
- *
- * This is effectively the previous value of [currentScene] which means that all caveats, for
- * example regarding when in a transition the current scene changes, apply.
- *
- * @param ignored If the previous scene is the same as [ignored], `null` is emitted. This is
- * designed to reduce the chances of a scene using [previousScene] naively to then set up a
- * user action that ends up leading to itself, which is an illegal operation that would cause
- * a crash.
- */
- fun previousScene(
- ignored: SceneKey? = null,
- ): StateFlow<SceneKey?> {
- fun SceneKey?.nullifyIfIgnored(): SceneKey? {
- return this?.takeIf { this != ignored }
- }
-
- return repository.previousScene
- .map { it.nullifyIfIgnored() }
- .stateIn(
- scope = applicationScope,
- started = SharingStarted.WhileSubscribed(),
- initialValue = repository.previousScene.value.nullifyIfIgnored(),
- )
- }
-
- /**
* Returns the keys of all scenes in the container.
*
* The scenes will be sorted in z-order such that the last one is the one that should be
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt
index 4fc24b8..39ec12f 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt
@@ -45,6 +45,7 @@
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.plugins.FalsingManager.FalsingBeliefListener
import com.android.systemui.power.domain.interactor.PowerInteractor
+import com.android.systemui.scene.domain.interactor.SceneBackInteractor
import com.android.systemui.scene.domain.interactor.SceneContainerOcclusionInteractor
import com.android.systemui.scene.domain.interactor.SceneInteractor
import com.android.systemui.scene.shared.flag.SceneContainerFlag
@@ -56,6 +57,7 @@
import com.android.systemui.statusbar.phone.CentralSurfaces
import com.android.systemui.statusbar.policy.domain.interactor.DeviceProvisioningInteractor
import com.android.systemui.util.asIndenting
+import com.android.systemui.util.kotlin.pairwise
import com.android.systemui.util.kotlin.sample
import com.android.systemui.util.printSection
import com.android.systemui.util.println
@@ -111,6 +113,7 @@
private val faceUnlockInteractor: DeviceEntryFaceAuthInteractor,
private val shadeInteractor: ShadeInteractor,
private val uiEventLogger: UiEventLogger,
+ private val sceneBackInteractor: SceneBackInteractor,
) : CoreStartable {
override fun start() {
@@ -124,6 +127,7 @@
hydrateInteractionState()
handleBouncerOverscroll()
hydrateWindowController()
+ hydrateBackStack()
} else {
sceneLogger.logFrameworkEnabled(
isEnabled = false,
@@ -257,8 +261,7 @@
// Track the previous scene (sans Bouncer), so that we know where to go when the device
// is unlocked whilst on the bouncer.
val previousScene =
- sceneInteractor
- .previousScene()
+ sceneBackInteractor.backScene
.filterNot { it == Scenes.Bouncer }
.stateIn(this, SharingStarted.Eagerly, initialValue = null)
deviceUnlockedInteractor.deviceUnlockStatus
@@ -581,4 +584,12 @@
loggingReason = loggingReason,
)
}
+
+ private fun hydrateBackStack() {
+ applicationScope.launch {
+ sceneInteractor.currentScene.pairwise().collect { (from, to) ->
+ sceneBackInteractor.onSceneChange(from = from, to = to)
+ }
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/shared/logger/SceneLogger.kt b/packages/SystemUI/src/com/android/systemui/scene/shared/logger/SceneLogger.kt
index f44779a..5ebdd86 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/shared/logger/SceneLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/shared/logger/SceneLogger.kt
@@ -20,6 +20,7 @@
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.core.LogLevel
import com.android.systemui.log.dagger.SceneFrameworkLog
+import java.util.Stack
import javax.inject.Inject
class SceneLogger @Inject constructor(@SceneFrameworkLog private val logBuffer: LogBuffer) {
@@ -102,7 +103,7 @@
tag = TAG,
level = LogLevel.INFO,
messageInitializer = { str1 = reason },
- messagePrinter = { "remote user interaction started, reason: $str3" },
+ messagePrinter = { "remote user interaction started, reason: $str1" },
)
}
@@ -115,6 +116,15 @@
)
}
+ fun logSceneBackStack(backStack: Stack<SceneKey>) {
+ logBuffer.log(
+ tag = TAG,
+ level = LogLevel.INFO,
+ messageInitializer = { str1 = backStack.joinToString(", ") { it.debugName } },
+ messagePrinter = { "back stack: $str1" },
+ )
+ }
+
companion object {
private const val TAG = "SceneFramework"
}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneContainerConfig.kt b/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneContainerConfig.kt
index 53cdaaa..0a30c31 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneContainerConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneContainerConfig.kt
@@ -25,6 +25,9 @@
* The keys to all scenes in the container, sorted by z-order such that the last one renders on
* top of all previous ones. Scene keys within the same container must not repeat but it's okay
* to have the same scene keys in different containers.
+ *
+ * Note that this doesn't control how back navigation works; for that, we have
+ * [navigationDistances].
*/
val sceneKeys: List<SceneKey>,
@@ -33,6 +36,24 @@
* before taking any application state in to account.
*/
val initialSceneKey: SceneKey,
+
+ /**
+ * Navigation distance of each scene.
+ *
+ * The navigation distance is a measure of how many non-back user action "steps" away from the
+ * starting scene, each scene is.
+ *
+ * The framework uses these to help scene implementations decide which scene to go back to when
+ * the user attempts to navigate back on them, if they need that.
+ *
+ * In general, the more non-back user actions are needed to get to a scene, the greater that
+ * scene's distance should be. Navigating "back" then goes from scenes with a higher distance to
+ * scenes with a lower distance.
+ *
+ * Note that this is not the z-order of rendering; that's determined by the order of declaration
+ * of scenes in the [sceneKeys] list.
+ */
+ val navigationDistances: Map<SceneKey, Int>
) {
init {
check(sceneKeys.isNotEmpty()) { "A container must have at least one scene key." }
@@ -40,5 +61,9 @@
check(sceneKeys.contains(initialSceneKey)) {
"The initial key \"$initialSceneKey\" is not present in this container."
}
+
+ check(navigationDistances.keys == sceneKeys.toSet()) {
+ "Scene keys and distance map must match."
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/OverlayActionChip.java b/packages/SystemUI/src/com/android/systemui/screenshot/OverlayActionChip.java
index 30f5e8b..9e68c48 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/OverlayActionChip.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/OverlayActionChip.java
@@ -32,7 +32,6 @@
import com.android.systemui.res.R;
-
/**
* View for a chip with an icon and text.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
index 501a4a7..494fc9b 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
@@ -97,7 +97,6 @@
import javax.inject.Provider;
-
/**
* Controls the state and flow for screenshots.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/SmartActionsReceiver.java b/packages/SystemUI/src/com/android/systemui/screenshot/SmartActionsReceiver.java
index ef58b9d..f8b22a6 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/SmartActionsReceiver.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/SmartActionsReceiver.java
@@ -31,7 +31,6 @@
import javax.inject.Inject;
-
/**
* Executes the smart action tapped by the user in the notification.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsService.java b/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsService.java
index c89b476..3bca4e4 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsService.java
@@ -38,9 +38,9 @@
import androidx.annotation.Nullable;
import com.android.internal.statusbar.IAppClipsService;
-import com.android.systemui.res.R;
import com.android.systemui.dagger.qualifiers.Application;
import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.res.R;
import com.android.wm.shell.bubbles.Bubbles;
import java.util.Optional;
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsTrampolineActivity.java b/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsTrampolineActivity.java
index a31b301..48449b3 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsTrampolineActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsTrampolineActivity.java
@@ -48,13 +48,13 @@
import com.android.internal.infra.ServiceConnector;
import com.android.internal.logging.UiEventLogger;
import com.android.internal.statusbar.IAppClipsService;
-import com.android.systemui.res.R;
import com.android.systemui.broadcast.BroadcastSender;
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.notetask.NoteTaskController;
import com.android.systemui.notetask.NoteTaskEntryPoint;
+import com.android.systemui.res.R;
import java.util.concurrent.Executor;
diff --git a/packages/SystemUI/src/com/android/systemui/scrim/ScrimView.java b/packages/SystemUI/src/com/android/systemui/scrim/ScrimView.java
index 20bd7c6..49f3cfc 100644
--- a/packages/SystemUI/src/com/android/systemui/scrim/ScrimView.java
+++ b/packages/SystemUI/src/com/android/systemui/scrim/ScrimView.java
@@ -44,7 +44,6 @@
import java.util.concurrent.Executor;
-
/**
* A view which can draw a scrim. This view maybe be used in multiple windows running on different
* threads, but is controlled by {@link com.android.systemui.statusbar.phone.ScrimController} so we
diff --git a/packages/SystemUI/src/com/android/systemui/settings/MultiUserUtilsModule.java b/packages/SystemUI/src/com/android/systemui/settings/MultiUserUtilsModule.java
index fd807db..05f19ef 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/MultiUserUtilsModule.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/MultiUserUtilsModule.java
@@ -36,11 +36,11 @@
import dagger.multibindings.ClassKey;
import dagger.multibindings.IntoMap;
-import javax.inject.Provider;
-
import kotlinx.coroutines.CoroutineDispatcher;
import kotlinx.coroutines.CoroutineScope;
+import javax.inject.Provider;
+
/**
* Dagger Module for classes found within the com.android.systemui.settings package.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt b/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt
index a5a5474..ff5fdc6 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt
@@ -17,6 +17,7 @@
package com.android.systemui.shade
import android.content.Context
+import android.graphics.Rect
import android.os.PowerManager
import android.os.SystemClock
import android.view.GestureDetector
@@ -215,6 +216,32 @@
R.dimen.communal_right_edge_swipe_region_width
)
+ val topEdgeSwipeRegionWidth =
+ containerView.resources.getDimensionPixelSize(
+ R.dimen.communal_top_edge_swipe_region_height
+ )
+ val bottomEdgeSwipeRegionWidth =
+ containerView.resources.getDimensionPixelSize(
+ R.dimen.communal_bottom_edge_swipe_region_height
+ )
+
+ // BouncerSwipeTouchHandler has a larger gesture area than we want, set an exclusion area so
+ // the gesture area doesn't overlap with widgets.
+ // TODO(b/323035776): adjust gesture areaa for portrait mode
+ containerView.repeatWhenAttached {
+ repeatOnLifecycle(Lifecycle.State.CREATED) {
+ val exclusionRect =
+ Rect(
+ 0,
+ topEdgeSwipeRegionWidth,
+ containerView.right,
+ containerView.bottom - bottomEdgeSwipeRegionWidth
+ )
+
+ containerView.systemGestureExclusionRects = listOf(exclusionRect)
+ }
+ }
+
collectFlow(
containerView,
keyguardTransitionInteractor.isFinishedInStateWhere(KeyguardState::isBouncerState),
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index aa915e3..67211b1 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -242,6 +242,9 @@
import kotlin.Unit;
+import kotlinx.coroutines.CoroutineDispatcher;
+import kotlinx.coroutines.flow.Flow;
+
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
@@ -251,9 +254,6 @@
import javax.inject.Inject;
import javax.inject.Provider;
-import kotlinx.coroutines.CoroutineDispatcher;
-import kotlinx.coroutines.flow.Flow;
-
@SysUISingleton
public final class NotificationPanelViewController implements ShadeSurface, Dumpable {
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt
index df9c57c..37da114 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt
@@ -59,10 +59,11 @@
import com.android.systemui.shade.carrier.ShadeCarrierGroup
import com.android.systemui.shade.carrier.ShadeCarrierGroupController
import com.android.systemui.statusbar.phone.StatusBarContentInsetsProvider
-import com.android.systemui.statusbar.phone.StatusBarIconController
import com.android.systemui.statusbar.phone.StatusBarLocation
import com.android.systemui.statusbar.phone.StatusIconContainer
import com.android.systemui.statusbar.phone.StatusOverlayHoverListenerFactory
+import com.android.systemui.statusbar.phone.ui.StatusBarIconController
+import com.android.systemui.statusbar.phone.ui.TintedIconManager
import com.android.systemui.statusbar.policy.Clock
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.statusbar.policy.NextAlarmController
@@ -88,7 +89,7 @@
constructor(
@Named(SHADE_HEADER) private val header: MotionLayout,
private val statusBarIconController: StatusBarIconController,
- private val tintedIconManagerFactory: StatusBarIconController.TintedIconManager.Factory,
+ private val tintedIconManagerFactory: TintedIconManager.Factory,
private val privacyIconsController: HeaderPrivacyIconsController,
private val insetsProvider: StatusBarContentInsetsProvider,
private val configurationController: ConfigurationController,
@@ -127,7 +128,7 @@
var shadeCollapseAction: Runnable? = null
- private lateinit var iconManager: StatusBarIconController.TintedIconManager
+ private lateinit var iconManager: TintedIconManager
private lateinit var carrierIconSlots: List<String>
private lateinit var mShadeCarrierGroupController: ShadeCarrierGroupController
@@ -303,10 +304,18 @@
// battery settings same as in QS icons
batteryMeterViewController.ignoreTunerUpdates()
+ val fgColor =
+ Utils.getColorAttrDefaultColor(header.context, android.R.attr.textColorPrimary)
+ val bgColor =
+ Utils.getColorAttrDefaultColor(header.context, android.R.attr.textColorPrimaryInverse)
+
iconManager = tintedIconManagerFactory.create(iconContainer, StatusBarLocation.QS)
- iconManager.setTint(
- Utils.getColorAttrDefaultColor(header.context, android.R.attr.textColorPrimary),
- Utils.getColorAttrDefaultColor(header.context, android.R.attr.textColorPrimaryInverse),
+ iconManager.setTint(fgColor, bgColor)
+
+ batteryIcon.updateColors(
+ fgColor /* foreground */,
+ bgColor /* background */,
+ fgColor /* single tone (current default) */
)
carrierIconSlots =
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt
index 4ec0b23..9dc19b1 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt
@@ -177,8 +177,7 @@
@Deprecated("This interface should not be used in scene container.")
interface ShadeViewStateProvider {
/** Returns the expanded height of the panel view. */
- @Deprecated("deprecated by migrate_keyguard_status_bar_view flag")
- val panelViewExpandedHeight: Float
+ @Deprecated("deprecated by SceneContainerFlag.isEnabled") val panelViewExpandedHeight: Float
/**
* Returns true if heads up should be visible.
@@ -189,6 +188,5 @@
@Deprecated("deprecated in Flexiglass.") fun shouldHeadsUpBeVisible(): Boolean
/** Return the fraction of the shade that's expanded, when in lockscreen. */
- @Deprecated("deprecated by migrate_keyguard_status_bar_view flag")
- val lockscreenShadeDragProgress: Float
+ @Deprecated("deprecated by SceneContainerFlag.isEnabled") val lockscreenShadeDragProgress: Float
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/carrier/ShadeCarrierGroupController.java b/packages/SystemUI/src/com/android/systemui/shade/carrier/ShadeCarrierGroupController.java
index c429329..e3d2f7d 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/carrier/ShadeCarrierGroupController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/carrier/ShadeCarrierGroupController.java
@@ -39,11 +39,11 @@
import com.android.keyguard.CarrierTextManager;
import com.android.settingslib.AccessibilityContentDescriptions;
import com.android.settingslib.mobile.TelephonyIcons;
-import com.android.systemui.res.R;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.res.R;
import com.android.systemui.statusbar.connectivity.MobileDataIndicators;
import com.android.systemui.statusbar.connectivity.NetworkController;
import com.android.systemui.statusbar.connectivity.SignalCallback;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/HeadsUpStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/HeadsUpStatusBarView.java
index 8d9fab1..d278b3e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/HeadsUpStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/HeadsUpStatusBarView.java
@@ -26,14 +26,13 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.keyguard.AlphaOptimizedLinearLayout;
-import com.android.systemui.res.R;
import com.android.systemui.plugins.DarkIconDispatcher;
+import com.android.systemui.res.R;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntry.OnSensitivityChangedListener;
import java.util.ArrayList;
-
/**
* The view in the statusBar that contains part of the heads-up information
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
index 0091bc5..854ef92 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
@@ -33,7 +33,6 @@
import android.annotation.UserIdInt;
import android.app.ActivityOptions;
import android.app.KeyguardManager;
-import android.app.Notification;
import android.app.admin.DevicePolicyManager;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -65,7 +64,6 @@
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FeatureFlagsClassic;
-import com.android.systemui.flags.Flags;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
import com.android.systemui.recents.OverviewProxyService;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/OperatorNameViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/OperatorNameViewController.java
index 6e7d8f4..0d789c7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/OperatorNameViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/OperatorNameViewController.java
@@ -34,10 +34,10 @@
import com.android.systemui.util.ViewController;
import com.android.systemui.util.kotlin.JavaAdapter;
-import javax.inject.Inject;
-
import kotlinx.coroutines.Job;
+import javax.inject.Inject;
+
/** Controller for {@link OperatorNameView}. */
public class OperatorNameViewController extends ViewController<OperatorNameView> {
private static final String KEY_SHOW_OPERATOR_NAME = "show_operator_name";
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/CallbackHandler.java b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/CallbackHandler.java
index 1638780..5391992 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/CallbackHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/CallbackHandler.java
@@ -32,7 +32,6 @@
import javax.inject.Inject;
-
/**
* Implements network listeners and forwards the calls along onto other listeners but on
* the current or specified Looper.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/SignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/SignalController.java
index 7e8f04e..2d2ee4a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/SignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/SignalController.java
@@ -29,7 +29,6 @@
import java.util.BitSet;
import java.util.List;
-
/**
* Common base class for handling signal for both wifi and mobile data.
*
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/WifiSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/WifiSignalController.java
index 08defcc..0e572be 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/WifiSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/WifiSignalController.java
@@ -34,8 +34,8 @@
import com.android.settingslib.graph.SignalDrawable;
import com.android.settingslib.mobile.TelephonyIcons;
import com.android.settingslib.wifi.WifiStatusTracker;
-import com.android.systemui.res.R;
import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.res.R;
import java.io.PrintWriter;
import java.util.BitSet;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java
index 594c191..8a53e0c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java
@@ -55,10 +55,10 @@
import com.android.systemui.statusbar.phone.CentralSurfacesImpl;
import com.android.systemui.statusbar.phone.ManagedProfileController;
import com.android.systemui.statusbar.phone.ManagedProfileControllerImpl;
-import com.android.systemui.statusbar.phone.StatusBarIconController;
-import com.android.systemui.statusbar.phone.StatusBarIconControllerImpl;
-import com.android.systemui.statusbar.phone.StatusBarIconList;
+import com.android.systemui.statusbar.phone.ui.StatusBarIconList;
import com.android.systemui.statusbar.phone.StatusBarRemoteInputCallback;
+import com.android.systemui.statusbar.phone.ui.StatusBarIconController;
+import com.android.systemui.statusbar.phone.ui.StatusBarIconControllerImpl;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import dagger.Binds;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java
index ad9e312..5bbd77e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java
@@ -49,10 +49,10 @@
import com.android.internal.messages.nano.SystemMessageProto;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.systemui.CoreStartable;
-import com.android.systemui.res.R;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dagger.qualifiers.UiBackground;
+import com.android.systemui.res.R;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.policy.KeyguardStateController;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
index 8b673c9..b397906 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
@@ -71,14 +71,14 @@
import com.android.systemui.statusbar.notification.stack.PriorityBucket;
import com.android.systemui.util.ListenerSet;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Objects;
-
import kotlinx.coroutines.flow.MutableStateFlow;
import kotlinx.coroutines.flow.StateFlow;
import kotlinx.coroutines.flow.StateFlowKt;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
/**
* Represents a notification that the system UI knows about
*
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/DeviceProvisionedCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/DeviceProvisionedCoordinator.java
index 0c95eab..7251607 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/DeviceProvisionedCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/DeviceProvisionedCoordinator.java
@@ -16,10 +16,8 @@
package com.android.systemui.statusbar.notification.collection.coordinator;
-import android.Manifest;
import android.app.Notification;
import android.content.pm.IPackageManager;
-import android.content.pm.PackageManager;
import android.os.RemoteException;
import android.service.notification.StatusBarNotification;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
index e31e9c2..91bb28e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
@@ -87,16 +87,18 @@
import com.android.systemui.statusbar.phone.StatusBarNotificationActivityStarter;
import com.android.systemui.statusbar.policy.HeadsUpManager;
-import javax.inject.Provider;
-
import dagger.Binds;
import dagger.Module;
import dagger.Provides;
import dagger.multibindings.ClassKey;
import dagger.multibindings.IntoMap;
+
import kotlin.coroutines.CoroutineContext;
+
import kotlinx.coroutines.CoroutineScope;
+import javax.inject.Provider;
+
/**
* Dagger Module for classes found within the com.android.systemui.statusbar.notification package.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLogger.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLogger.java
index 6c63d1d..89aa3ab 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLogger.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLogger.java
@@ -33,6 +33,7 @@
import com.android.systemui.statusbar.notification.stack.PriorityBucket;
import java.util.List;
+
/**
* Statsd logging for notification panel.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HeadsUpStyleProvider.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HeadsUpStyleProvider.kt
new file mode 100644
index 0000000..816e5c1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HeadsUpStyleProvider.kt
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar.notification.row
+
+import android.app.Flags
+import javax.inject.Inject
+
+/**
+ * A class managing the heads up style to be applied based on user settings, immersive mode and
+ * other factors.
+ */
+interface HeadsUpStyleProvider {
+ fun shouldApplyCompactStyle(): Boolean
+}
+
+class HeadsUpStyleProviderImpl @Inject constructor() : HeadsUpStyleProvider {
+
+ /**
+ * TODO(b/270709257) This feature is under development. This method returns Compact when the
+ * flag is enabled for fish fooding purpose.
+ */
+ override fun shouldApplyCompactStyle(): Boolean = Flags.compactHeadsUpNotification()
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
index 31e69c9..2f03871 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
@@ -90,6 +90,8 @@
private final Executor mInflationExecutor;
private final SmartReplyStateInflater mSmartReplyStateInflater;
private final NotifLayoutInflaterFactory.Provider mNotifLayoutInflaterFactoryProvider;
+ private final HeadsUpStyleProvider mHeadsUpStyleProvider;
+
private final NotificationContentInflaterLogger mLogger;
@Inject
@@ -101,6 +103,7 @@
@NotifInflation Executor inflationExecutor,
SmartReplyStateInflater smartRepliesInflater,
NotifLayoutInflaterFactory.Provider notifLayoutInflaterFactoryProvider,
+ HeadsUpStyleProvider headsUpStyleProvider,
NotificationContentInflaterLogger logger) {
mRemoteViewCache = remoteViewCache;
mRemoteInputManager = remoteInputManager;
@@ -109,6 +112,7 @@
mInflationExecutor = inflationExecutor;
mSmartReplyStateInflater = smartRepliesInflater;
mNotifLayoutInflaterFactoryProvider = notifLayoutInflaterFactoryProvider;
+ mHeadsUpStyleProvider = headsUpStyleProvider;
mLogger = logger;
}
@@ -158,6 +162,7 @@
/* isMediaFlagEnabled = */ mIsMediaInQS,
mSmartReplyStateInflater,
mNotifLayoutInflaterFactoryProvider,
+ mHeadsUpStyleProvider,
mLogger);
if (mInflateSynchronously) {
task.onPostExecute(task.doInBackground());
@@ -184,6 +189,7 @@
packageContext,
row,
mNotifLayoutInflaterFactoryProvider,
+ mHeadsUpStyleProvider,
mLogger);
result = inflateSmartReplyViews(result, reInflateFlags, entry, row.getContext(),
@@ -370,6 +376,7 @@
boolean usesIncreasedHeadsUpHeight, Context packageContext,
ExpandableNotificationRow row,
NotifLayoutInflaterFactory.Provider notifLayoutInflaterFactoryProvider,
+ HeadsUpStyleProvider headsUpStyleProvider,
NotificationContentInflaterLogger logger) {
return TraceUtils.trace("NotificationContentInflater.createRemoteViews", () -> {
InflationProgress result = new InflationProgress();
@@ -388,8 +395,13 @@
if ((reInflateFlags & FLAG_CONTENT_VIEW_HEADS_UP) != 0) {
logger.logAsyncTaskProgress(entryForLogging, "creating heads up remote view");
- result.newHeadsUpView = builder.createHeadsUpContentView(
- usesIncreasedHeadsUpHeight);
+ final boolean isHeadsUpCompact = headsUpStyleProvider.shouldApplyCompactStyle();
+ if (isHeadsUpCompact) {
+ result.newHeadsUpView = builder.createCompactHeadsUpContentView();
+ } else {
+ result.newHeadsUpView = builder.createHeadsUpContentView(
+ usesIncreasedHeadsUpHeight);
+ }
}
if ((reInflateFlags & FLAG_CONTENT_VIEW_PUBLIC) != 0) {
@@ -1067,6 +1079,7 @@
private final boolean mIsMediaInQS;
private final SmartReplyStateInflater mSmartRepliesInflater;
private final NotifLayoutInflaterFactory.Provider mNotifLayoutInflaterFactoryProvider;
+ private final HeadsUpStyleProvider mHeadsUpStyleProvider;
private final NotificationContentInflaterLogger mLogger;
private AsyncInflationTask(
@@ -1085,6 +1098,7 @@
boolean isMediaFlagEnabled,
SmartReplyStateInflater smartRepliesInflater,
NotifLayoutInflaterFactory.Provider notifLayoutInflaterFactoryProvider,
+ HeadsUpStyleProvider headsUpStyleProvider,
NotificationContentInflaterLogger logger) {
mEntry = entry;
mRow = row;
@@ -1102,6 +1116,7 @@
mConversationProcessor = conversationProcessor;
mIsMediaInQS = isMediaFlagEnabled;
mNotifLayoutInflaterFactoryProvider = notifLayoutInflaterFactoryProvider;
+ mHeadsUpStyleProvider = headsUpStyleProvider;
mLogger = logger;
entry.setInflationTask(this);
}
@@ -1166,7 +1181,7 @@
InflationProgress inflationProgress = createRemoteViews(mReInflateFlags,
recoveredBuilder, mIsMinimized, mUsesIncreasedHeight,
mUsesIncreasedHeadsUpHeight, packageContext, mRow,
- mNotifLayoutInflaterFactoryProvider, mLogger);
+ mNotifLayoutInflaterFactoryProvider, mHeadsUpStyleProvider, mLogger);
mLogger.logAsyncTaskProgress(mEntry,
"getting existing smart reply state (on wrong thread!)");
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java
index a317f95..c10c09c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java
@@ -41,8 +41,8 @@
import com.android.app.animation.Interpolators;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.res.R;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
+import com.android.systemui.res.R;
import com.android.systemui.statusbar.AlphaOptimizedImageView;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowModule.java
index 200a08a..17c2026 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowModule.java
@@ -50,4 +50,12 @@
@SysUISingleton
public abstract NotifRemoteViewsFactoryContainer provideNotifRemoteViewsFactoryContainer(
NotifRemoteViewsFactoryContainerImpl containerImpl);
+
+ /**
+ * Provides heads up style manager
+ */
+ @Binds
+ @SysUISingleton
+ public abstract HeadsUpStyleProvider provideHeadsUpStyleManager(
+ HeadsUpStyleProviderImpl headsUpStyleManagerImpl);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PartialConversationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PartialConversationInfo.java
index 53f7d4b..60e98a5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PartialConversationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PartialConversationInfo.java
@@ -37,8 +37,6 @@
import com.android.systemui.res.R;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import java.util.Set;
-
/**
* The guts of a conversation notification that doesn't use valid shortcuts that is revealed when
* performing a long press.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/SingleLineViewInflater.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/SingleLineViewInflater.kt
index d3c874c..3fce9ce 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/SingleLineViewInflater.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/SingleLineViewInflater.kt
@@ -217,8 +217,9 @@
var currentGroup: MutableList<MessagingStyle.Message>? = null
var currentSenderKey: CharSequence? = null
val groups = mutableListOf<MutableList<MessagingStyle.Message>>()
- for (i in 0 until (historicMessages.size + messages.size)) {
- val message = if (i < historicMessages.size) historicMessages[i] else messages[i]
+ val histSize = historicMessages.size
+ for (i in 0 until (histSize + messages.size)) {
+ val message = if (i < histSize) historicMessages[i] else messages[i - histSize]
val sender = message.senderPerson
val senderKey = sender?.getKeyOrName()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCompactHeadsUpTemplateViewWrapper.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCompactHeadsUpTemplateViewWrapper.kt
new file mode 100644
index 0000000..ce87d2f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCompactHeadsUpTemplateViewWrapper.kt
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar.notification.row.wrapper
+
+import android.content.Context
+import android.view.View
+import com.android.systemui.statusbar.notification.FeedbackIcon
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
+
+/**
+ * Compact Heads up Notifications template that doesn't set feedback icon and audibly alert icons
+ */
+class NotificationCompactHeadsUpTemplateViewWrapper(
+ ctx: Context,
+ view: View,
+ row: ExpandableNotificationRow
+) : NotificationTemplateViewWrapper(ctx, view, row) {
+ override fun setFeedbackIcon(icon: FeedbackIcon?) = Unit
+ override fun setRecentlyAudiblyAlerted(audiblyAlerted: Boolean) = Unit
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationTemplateViewWrapper.java
index 91b12cc..df43ff1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationTemplateViewWrapper.java
@@ -41,8 +41,8 @@
import com.android.internal.util.ContrastColorUtil;
import com.android.internal.widget.NotificationActionListLayout;
import com.android.systemui.Dependency;
-import com.android.systemui.res.R;
import com.android.systemui.UiOffloadThread;
+import com.android.systemui.res.R;
import com.android.systemui.statusbar.CrossFadeHelper;
import com.android.systemui.statusbar.TransformableView;
import com.android.systemui.statusbar.ViewTransformationHelper;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java
index 50f3e78..4244542 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java
@@ -72,7 +72,10 @@
return new NotificationConversationTemplateViewWrapper(ctx, v, row);
} else if ("call".equals(v.getTag())) {
return new NotificationCallTemplateViewWrapper(ctx, v, row);
+ } else if ("compactHUN".equals((v.getTag()))) {
+ return new NotificationCompactHeadsUpTemplateViewWrapper(ctx, v, row);
}
+
if (row.getEntry().getSbn().getNotification().isStyle(
Notification.DecoratedCustomViewStyle.class)) {
return new NotificationDecoratedCustomViewWrapper(ctx, v, row);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
index dedf366..e520957 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
@@ -38,6 +38,7 @@
import com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm.BypassController;
import com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm.SectionProvider;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
+import com.android.systemui.statusbar.policy.AvalancheController;
import java.io.PrintWriter;
@@ -56,6 +57,8 @@
private final SectionProvider mSectionProvider;
private final BypassController mBypassController;
private final LargeScreenShadeInterpolator mLargeScreenShadeInterpolator;
+ private final AvalancheController mAvalancheController;
+
/**
* Used to read bouncer states.
*/
@@ -269,12 +272,14 @@
@NonNull SectionProvider sectionProvider,
@NonNull BypassController bypassController,
@Nullable StatusBarKeyguardViewManager statusBarKeyguardViewManager,
- @NonNull LargeScreenShadeInterpolator largeScreenShadeInterpolator
+ @NonNull LargeScreenShadeInterpolator largeScreenShadeInterpolator,
+ AvalancheController avalancheController
) {
mSectionProvider = sectionProvider;
mBypassController = bypassController;
mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
mLargeScreenShadeInterpolator = largeScreenShadeInterpolator;
+ mAvalancheController = avalancheController;
reload(context);
dumpManager.registerDumpable(this);
}
@@ -287,6 +292,14 @@
mBaseZHeight = getBaseHeight(mZDistanceBetweenElements);
}
+ String getAvalancheShowingHunKey() {
+ return mAvalancheController.getShowingHunKey();
+ }
+
+ String getAvalanchePreviousHunKey() {
+ return mAvalancheController.getPreviousHunKey();
+ }
+
void setOverExpansion(float overExpansion) {
mOverExpansion = overExpansion;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java
index ab62ed6..5963d35 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java
@@ -29,7 +29,6 @@
import com.android.app.animation.Interpolators;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.keyguard.KeyguardSliceView;
import com.android.systemui.res.R;
import com.android.systemui.shared.clocks.AnimatableClockView;
import com.android.systemui.statusbar.NotificationShelf;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java
index eb81c46..1358cfd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java
@@ -30,7 +30,6 @@
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.dump.DumpManager;
import com.android.systemui.statusbar.AutoHideUiElement;
import java.io.PrintWriter;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DarkIconDispatcherImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DarkIconDispatcherImpl.java
index d513f8d..398c1d4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DarkIconDispatcherImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DarkIconDispatcherImpl.java
@@ -14,8 +14,8 @@
package com.android.systemui.statusbar.phone;
-import static com.android.systemui.plugins.DarkIconDispatcher.getTint;
import static com.android.settingslib.flags.Flags.newStatusBarIcons;
+import static com.android.systemui.plugins.DarkIconDispatcher.getTint;
import android.animation.ArgbEvaluator;
import android.content.Context;
@@ -28,16 +28,16 @@
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dump.DumpManager;
-import java.io.PrintWriter;
-import java.util.ArrayList;
-
-import javax.inject.Inject;
-
import kotlinx.coroutines.flow.FlowKt;
import kotlinx.coroutines.flow.MutableStateFlow;
import kotlinx.coroutines.flow.StateFlow;
import kotlinx.coroutines.flow.StateFlowKt;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+
+import javax.inject.Inject;
+
/**
*/
@SysUISingleton
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java
index 033659b..3063aed 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java
@@ -57,12 +57,12 @@
import dagger.Lazy;
+import kotlinx.coroutines.ExperimentalCoroutinesApi;
+
import java.util.ArrayList;
import javax.inject.Inject;
-import kotlinx.coroutines.ExperimentalCoroutinesApi;
-
/**
* Implementation of DozeHost for SystemUI.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
index 8ec8d1c..68457ea 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
@@ -58,6 +58,11 @@
import com.android.systemui.util.settings.GlobalSettings;
import com.android.systemui.util.time.SystemClock;
+import kotlinx.coroutines.flow.Flow;
+import kotlinx.coroutines.flow.MutableStateFlow;
+import kotlinx.coroutines.flow.StateFlow;
+import kotlinx.coroutines.flow.StateFlowKt;
+
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashSet;
@@ -68,11 +73,6 @@
import javax.inject.Inject;
-import kotlinx.coroutines.flow.Flow;
-import kotlinx.coroutines.flow.MutableStateFlow;
-import kotlinx.coroutines.flow.StateFlow;
-import kotlinx.coroutines.flow.StateFlowKt;
-
/** A implementation of HeadsUpManager for phone. */
@SysUISingleton
public class HeadsUpManagerPhone extends BaseHeadsUpManager implements
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardDismissHandler.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardDismissHandler.java
index f043fcf..abfe6a2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardDismissHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardDismissHandler.java
@@ -18,7 +18,6 @@
import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
-
/** Executes actions that require the screen to be unlocked. */
public interface KeyguardDismissHandler {
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextView.java
index c6690c9..c4e0f31 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextView.java
@@ -32,8 +32,8 @@
import com.android.app.animation.Interpolators;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.res.R;
import com.android.systemui.keyguard.KeyguardIndication;
+import com.android.systemui.res.R;
/**
* A view to show hints on Keyguard ("Swipe up to unlock", "Tap again to open").
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
index 302bdcc..3cdf68f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
@@ -48,18 +48,19 @@
import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
import com.android.systemui.res.R;
import com.android.systemui.statusbar.phone.SysuiDarkIconDispatcher.DarkChange;
+import com.android.systemui.statusbar.phone.ui.TintedIconManager;
import com.android.systemui.statusbar.phone.userswitcher.StatusBarUserSwitcherContainer;
import com.android.systemui.user.ui.binder.StatusBarUserChipViewBinder;
import com.android.systemui.user.ui.viewmodel.StatusBarUserChipViewModel;
-import java.io.PrintWriter;
-import java.util.ArrayList;
-
import kotlinx.coroutines.flow.FlowKt;
import kotlinx.coroutines.flow.MutableStateFlow;
import kotlinx.coroutines.flow.StateFlow;
import kotlinx.coroutines.flow.StateFlowKt;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+
/**
* The header group on Keyguard.
*/
@@ -421,7 +422,7 @@
}
/** Should only be called from {@link KeyguardStatusBarViewController}. */
- void onThemeChanged(StatusBarIconController.TintedIconManager iconManager) {
+ void onThemeChanged(TintedIconManager iconManager) {
mBatteryView.setColorsFromContext(mContext);
updateIconsAndTextColors(iconManager);
}
@@ -438,7 +439,7 @@
}
}
- private void updateIconsAndTextColors(StatusBarIconController.TintedIconManager iconManager) {
+ private void updateIconsAndTextColors(TintedIconManager iconManager) {
@ColorInt int textColor = Utils.getColorAttrDefaultColor(mContext,
R.attr.wallpaperTextColor);
float luminance = Color.luminance(textColor);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
index 3343779..45d86c0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
@@ -19,8 +19,8 @@
import static android.app.StatusBarManager.DISABLE2_SYSTEM_ICONS;
import static android.app.StatusBarManager.DISABLE_SYSTEM_INFO;
-import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
import static com.android.systemui.Flags.updateUserSwitcherBackground;
+import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
import android.content.res.Configuration;
import android.content.res.Resources;
@@ -46,11 +46,10 @@
import com.android.systemui.battery.BatteryMeterViewController;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.flags.FeatureFlags;
-import com.android.systemui.flags.Flags;
import com.android.systemui.log.core.LogLevel;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.res.R;
+import com.android.systemui.scene.shared.flag.SceneContainerFlag;
import com.android.systemui.shade.ShadeViewStateProvider;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.NotificationMediaManager;
@@ -65,6 +64,8 @@
import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
import com.android.systemui.statusbar.phone.fragment.StatusBarIconBlocklistKt;
import com.android.systemui.statusbar.phone.fragment.StatusBarSystemEventDefaultAnimator;
+import com.android.systemui.statusbar.phone.ui.StatusBarIconController;
+import com.android.systemui.statusbar.phone.ui.TintedIconManager;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -108,7 +109,7 @@
private final BatteryController mBatteryController;
private final UserInfoController mUserInfoController;
private final StatusBarIconController mStatusBarIconController;
- private final StatusBarIconController.TintedIconManager.Factory mTintedIconManagerFactory;
+ private final TintedIconManager.Factory mTintedIconManagerFactory;
private final BatteryMeterViewController mBatteryMeterViewController;
private final ShadeViewStateProvider mShadeViewStateProvider;
private final KeyguardStateController mKeyguardStateController;
@@ -118,7 +119,6 @@
private final BiometricUnlockController mBiometricUnlockController;
private final SysuiStatusBarStateController mStatusBarStateController;
private final StatusBarContentInsetsProvider mInsetsProvider;
- private final FeatureFlags mFeatureFlags;
private final UserManager mUserManager;
private final StatusBarUserChipViewModel mStatusBarUserChipViewModel;
private final SecureSettings mSecureSettings;
@@ -250,7 +250,7 @@
private final int mNotificationsHeaderCollideDistance;
private boolean mBatteryListening;
- private StatusBarIconController.TintedIconManager mTintedIconManager;
+ private TintedIconManager mTintedIconManager;
private float mKeyguardStatusBarAnimateAlpha = 1f;
/**
@@ -283,7 +283,7 @@
BatteryController batteryController,
UserInfoController userInfoController,
StatusBarIconController statusBarIconController,
- StatusBarIconController.TintedIconManager.Factory tintedIconManagerFactory,
+ TintedIconManager.Factory tintedIconManagerFactory,
BatteryMeterViewController batteryMeterViewController,
ShadeViewStateProvider shadeViewStateProvider,
KeyguardStateController keyguardStateController,
@@ -293,7 +293,6 @@
BiometricUnlockController biometricUnlockController,
SysuiStatusBarStateController statusBarStateController,
StatusBarContentInsetsProvider statusBarContentInsetsProvider,
- FeatureFlags featureFlags,
UserManager userManager,
StatusBarUserChipViewModel userChipViewModel,
SecureSettings secureSettings,
@@ -321,7 +320,6 @@
mBiometricUnlockController = biometricUnlockController;
mStatusBarStateController = statusBarStateController;
mInsetsProvider = statusBarContentInsetsProvider;
- mFeatureFlags = featureFlags;
mUserManager = userManager;
mStatusBarUserChipViewModel = userChipViewModel;
mSecureSettings = secureSettings;
@@ -707,7 +705,7 @@
}
private boolean isMigrationEnabled() {
- return mFeatureFlags.isEnabled(Flags.MIGRATE_KEYGUARD_STATUS_BAR_VIEW);
+ return SceneContainerFlag.isEnabled();
}
private final ContentObserver mVolumeSettingObserver = new ContentObserver(null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index d975009..3c68805 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -44,7 +44,6 @@
import androidx.lifecycle.Observer;
-import com.android.systemui.res.R;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.qualifiers.DisplayId;
import com.android.systemui.dagger.qualifiers.Main;
@@ -56,9 +55,11 @@
import com.android.systemui.privacy.logging.PrivacyLogger;
import com.android.systemui.qs.tiles.DndTile;
import com.android.systemui.qs.tiles.RotationLockTile;
+import com.android.systemui.res.R;
import com.android.systemui.screenrecord.RecordingController;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.phone.ui.StatusBarIconController;
import com.android.systemui.statusbar.policy.BluetoothController;
import com.android.systemui.statusbar.policy.CastController;
import com.android.systemui.statusbar.policy.CastController.CastDevice;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 02293a2..0a88d63 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -83,6 +83,8 @@
import com.android.systemui.util.wakelock.WakeLock;
import com.android.systemui.wallpapers.data.repository.WallpaperRepository;
+import kotlinx.coroutines.CoroutineDispatcher;
+
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -91,8 +93,6 @@
import javax.inject.Inject;
-import kotlinx.coroutines.CoroutineDispatcher;
-
/**
* Controls both the scrim behind the notifications and in front of the notifications (when a
* security method gets shown).
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
deleted file mode 100644
index d7cbe5d..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
+++ /dev/null
@@ -1,602 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the specific language governing
- * permissions and limitations under the License.
- */
-
-package com.android.systemui.statusbar.phone;
-
-import static com.android.systemui.statusbar.phone.StatusBarIconHolder.TYPE_BINDABLE;
-import static com.android.systemui.statusbar.phone.StatusBarIconHolder.TYPE_ICON;
-import static com.android.systemui.statusbar.phone.StatusBarIconHolder.TYPE_MOBILE_NEW;
-import static com.android.systemui.statusbar.phone.StatusBarIconHolder.TYPE_WIFI_NEW;
-
-import android.annotation.Nullable;
-import android.content.Context;
-import android.os.Bundle;
-import android.text.TextUtils;
-import android.util.ArraySet;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.LinearLayout;
-import android.widget.LinearLayout.LayoutParams;
-
-import androidx.annotation.VisibleForTesting;
-
-import com.android.internal.statusbar.StatusBarIcon;
-import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.demomode.DemoModeCommandReceiver;
-import com.android.systemui.plugins.DarkIconDispatcher;
-import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
-import com.android.systemui.res.R;
-import com.android.systemui.statusbar.BaseStatusBarFrameLayout;
-import com.android.systemui.statusbar.StatusBarIconView;
-import com.android.systemui.statusbar.StatusIconDisplayable;
-import com.android.systemui.statusbar.connectivity.ui.MobileContextProvider;
-import com.android.systemui.statusbar.phone.StatusBarIconHolder.BindableIconHolder;
-import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.CallIndicatorIconState;
-import com.android.systemui.statusbar.pipeline.mobile.ui.MobileUiAdapter;
-import com.android.systemui.statusbar.pipeline.mobile.ui.binder.MobileIconsBinder;
-import com.android.systemui.statusbar.pipeline.mobile.ui.view.ModernStatusBarMobileView;
-import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconsViewModel;
-import com.android.systemui.statusbar.pipeline.shared.ui.view.ModernStatusBarView;
-import com.android.systemui.statusbar.pipeline.wifi.ui.WifiUiAdapter;
-import com.android.systemui.statusbar.pipeline.wifi.ui.view.ModernStatusBarWifiView;
-import com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel.LocationBasedWifiViewModel;
-import com.android.systemui.util.Assert;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.inject.Inject;
-
-public interface StatusBarIconController {
-
- /**
- * When an icon is added with TAG_PRIMARY, it will be treated as the primary icon
- * in that slot and not added as a sub slot.
- */
- int TAG_PRIMARY = 0;
-
- /** */
- void addIconGroup(IconManager iconManager);
- /** */
- void removeIconGroup(IconManager iconManager);
-
- /** Refresh the state of an IconManager by recreating the views */
- void refreshIconGroup(IconManager iconManager);
-
- /**
- * Adds or updates an icon that comes from an active tile service.
- *
- * If the icon is null, the icon will be removed.
- */
- void setIconFromTile(String slot, @Nullable StatusBarIcon icon);
-
- /** Removes an icon that had come from an active tile service. */
- void removeIconForTile(String slot);
-
- /** Adds or updates an icon for the given slot for **internal system icons**. */
- void setIcon(String slot, int resourceId, CharSequence contentDescription);
-
- /**
- * Sets up a wifi icon using the new data pipeline. No effect if the wifi icon has already been
- * set up (inflated and added to the view hierarchy).
- */
- void setNewWifiIcon();
-
- /**
- * Notify this class that there is a new set of mobile icons to display, keyed off of this list
- * of subIds. The icons will be added and bound to the mobile data pipeline via
- * {@link com.android.systemui.statusbar.pipeline.mobile.ui.binder.MobileIconBinder}.
- */
- void setNewMobileIconSubIds(List<Integer> subIds);
- /**
- * Display the no calling & SMS icons.
- */
- void setCallStrengthIcons(String slot, List<CallIndicatorIconState> states);
-
- /**
- * Display the no calling & SMS icons.
- */
- void setNoCallingIcons(String slot, List<CallIndicatorIconState> states);
-
- public void setIconVisibility(String slot, boolean b);
-
- /**
- * Sets the live region mode for the icon
- *
- * @param slot Icon slot to set region for
- * @param accessibilityLiveRegion live region mode for the icon
- * @see android.view.View#setAccessibilityLiveRegion(int)
- */
- void setIconAccessibilityLiveRegion(String slot, int accessibilityLiveRegion);
-
- /**
- * If you don't know what to pass for `tag`, either remove all icons for slot, or use
- * TAG_PRIMARY to refer to the first icon at a given slot.
- */
- void removeIcon(String slot, int tag);
-
- // TODO: See if we can rename this tunable name.
- String ICON_HIDE_LIST = "icon_blacklist";
-
- /** Reads the default hide list from config value unless hideListStr is provided. */
- static ArraySet<String> getIconHideList(Context context, String hideListStr) {
- ArraySet<String> ret = new ArraySet<>();
- String[] hideList = hideListStr == null
- ? context.getResources().getStringArray(R.array.config_statusBarIconsToExclude)
- : hideListStr.split(",");
- for (String slot : hideList) {
- if (!TextUtils.isEmpty(slot)) {
- ret.add(slot);
- }
- }
- return ret;
- }
-
- /**
- * Version of ViewGroup that observes state from the DarkIconDispatcher.
- */
- class DarkIconManager extends IconManager {
- private final DarkIconDispatcher mDarkIconDispatcher;
- private final int mIconHorizontalMargin;
-
- public DarkIconManager(
- LinearLayout linearLayout,
- StatusBarLocation location,
- WifiUiAdapter wifiUiAdapter,
- MobileUiAdapter mobileUiAdapter,
- MobileContextProvider mobileContextProvider,
- DarkIconDispatcher darkIconDispatcher) {
- super(linearLayout,
- location,
- wifiUiAdapter,
- mobileUiAdapter,
- mobileContextProvider);
- mIconHorizontalMargin = mContext.getResources().getDimensionPixelSize(
- R.dimen.status_bar_icon_horizontal_margin);
- mDarkIconDispatcher = darkIconDispatcher;
- }
-
- @Override
- protected void onIconAdded(int index, String slot, boolean blocked,
- StatusBarIconHolder holder) {
- StatusIconDisplayable view = addHolder(index, slot, blocked, holder);
- mDarkIconDispatcher.addDarkReceiver((DarkReceiver) view);
- }
-
- @Override
- protected LayoutParams onCreateLayoutParams() {
- LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
- ViewGroup.LayoutParams.WRAP_CONTENT, mIconSize);
- lp.setMargins(mIconHorizontalMargin, 0, mIconHorizontalMargin, 0);
- return lp;
- }
-
- @Override
- protected void destroy() {
- for (int i = 0; i < mGroup.getChildCount(); i++) {
- mDarkIconDispatcher.removeDarkReceiver((DarkReceiver) mGroup.getChildAt(i));
- }
- mGroup.removeAllViews();
- }
-
- @Override
- protected void onRemoveIcon(int viewIndex) {
- mDarkIconDispatcher.removeDarkReceiver((DarkReceiver) mGroup.getChildAt(viewIndex));
- super.onRemoveIcon(viewIndex);
- }
-
- @Override
- public void onSetIcon(int viewIndex, StatusBarIcon icon) {
- super.onSetIcon(viewIndex, icon);
- mDarkIconDispatcher.applyDark((DarkReceiver) mGroup.getChildAt(viewIndex));
- }
-
- @Override
- protected DemoStatusIcons createDemoStatusIcons() {
- DemoStatusIcons icons = super.createDemoStatusIcons();
- mDarkIconDispatcher.addDarkReceiver(icons);
-
- return icons;
- }
-
- @Override
- protected void exitDemoMode() {
- mDarkIconDispatcher.removeDarkReceiver(mDemoStatusIcons);
- super.exitDemoMode();
- }
-
- @SysUISingleton
- public static class Factory {
- private final WifiUiAdapter mWifiUiAdapter;
- private final MobileContextProvider mMobileContextProvider;
- private final MobileUiAdapter mMobileUiAdapter;
- private final DarkIconDispatcher mDarkIconDispatcher;
-
- @Inject
- public Factory(
- WifiUiAdapter wifiUiAdapter,
- MobileContextProvider mobileContextProvider,
- MobileUiAdapter mobileUiAdapter,
- DarkIconDispatcher darkIconDispatcher) {
- mWifiUiAdapter = wifiUiAdapter;
- mMobileContextProvider = mobileContextProvider;
- mMobileUiAdapter = mobileUiAdapter;
- mDarkIconDispatcher = darkIconDispatcher;
- }
-
- public DarkIconManager create(LinearLayout group, StatusBarLocation location) {
- return new DarkIconManager(
- group,
- location,
- mWifiUiAdapter,
- mMobileUiAdapter,
- mMobileContextProvider,
- mDarkIconDispatcher);
- }
- }
- }
-
- /**
- *
- */
- class TintedIconManager extends IconManager {
- // The main tint, used as the foreground in non layer drawables
- private int mColor;
- // To be used as the main tint in drawables that wish to have a layer
- private int mForegroundColor;
-
- public TintedIconManager(
- ViewGroup group,
- StatusBarLocation location,
- WifiUiAdapter wifiUiAdapter,
- MobileUiAdapter mobileUiAdapter,
- MobileContextProvider mobileContextProvider
- ) {
- super(group,
- location,
- wifiUiAdapter,
- mobileUiAdapter,
- mobileContextProvider);
- }
-
- @Override
- protected void onIconAdded(int index, String slot, boolean blocked,
- StatusBarIconHolder holder) {
- StatusIconDisplayable view = addHolder(index, slot, blocked, holder);
- view.setStaticDrawableColor(mColor, mForegroundColor);
- view.setDecorColor(mColor);
- }
-
- /**
- * Most icons are a single layer, and tintColor will be used as the tint in those cases.
- * For icons that have a background, foregroundColor becomes the contrasting tint used
- * for the foreground.
- *
- * @param tintColor the main tint to use for the icons in the group
- * @param foregroundColor used as the main tint for layer-ish drawables where tintColor is
- * being used as the background
- */
- public void setTint(int tintColor, int foregroundColor) {
- mColor = tintColor;
- mForegroundColor = foregroundColor;
-
- for (int i = 0; i < mGroup.getChildCount(); i++) {
- View child = mGroup.getChildAt(i);
- if (child instanceof StatusIconDisplayable) {
- StatusIconDisplayable icon = (StatusIconDisplayable) child;
- icon.setStaticDrawableColor(mColor, mForegroundColor);
- icon.setDecorColor(mColor);
- }
- }
-
- if (mDemoStatusIcons != null) {
- mDemoStatusIcons.setColor(tintColor, foregroundColor);
- }
- }
-
- @Override
- protected DemoStatusIcons createDemoStatusIcons() {
- DemoStatusIcons icons = super.createDemoStatusIcons();
- icons.setColor(mColor, mForegroundColor);
- return icons;
- }
-
- @SysUISingleton
- public static class Factory {
- private final WifiUiAdapter mWifiUiAdapter;
- private final MobileContextProvider mMobileContextProvider;
- private final MobileUiAdapter mMobileUiAdapter;
-
- @Inject
- public Factory(
- WifiUiAdapter wifiUiAdapter,
- MobileUiAdapter mobileUiAdapter,
- MobileContextProvider mobileContextProvider
- ) {
- mWifiUiAdapter = wifiUiAdapter;
- mMobileUiAdapter = mobileUiAdapter;
- mMobileContextProvider = mobileContextProvider;
- }
-
- public TintedIconManager create(ViewGroup group, StatusBarLocation location) {
- return new TintedIconManager(
- group,
- location,
- mWifiUiAdapter,
- mMobileUiAdapter,
- mMobileContextProvider);
- }
- }
- }
-
- /**
- * Turns info from StatusBarIconController into ImageViews in a ViewGroup.
- */
- class IconManager implements DemoModeCommandReceiver {
- protected final ViewGroup mGroup;
- private final MobileContextProvider mMobileContextProvider;
- private final LocationBasedWifiViewModel mWifiViewModel;
- private final MobileIconsViewModel mMobileIconsViewModel;
-
- protected final Context mContext;
- protected int mIconSize;
- // Whether or not these icons show up in dumpsys
- protected boolean mShouldLog = false;
- private StatusBarIconController mController;
- private final StatusBarLocation mLocation;
-
- // Enables SystemUI demo mode to take effect in this group
- protected boolean mDemoable = true;
- private boolean mIsInDemoMode;
- protected DemoStatusIcons mDemoStatusIcons;
-
- protected ArrayList<String> mBlockList = new ArrayList<>();
-
- public IconManager(
- ViewGroup group,
- StatusBarLocation location,
- WifiUiAdapter wifiUiAdapter,
- MobileUiAdapter mobileUiAdapter,
- MobileContextProvider mobileContextProvider
- ) {
- mGroup = group;
- mMobileContextProvider = mobileContextProvider;
- mContext = group.getContext();
- mLocation = location;
-
- reloadDimens();
-
- // This starts the flow for the new pipeline, and will notify us of changes via
- // {@link #setNewMobileIconIds}
- mMobileIconsViewModel = mobileUiAdapter.getMobileIconsViewModel();
- MobileIconsBinder.bind(mGroup, mMobileIconsViewModel);
-
- mWifiViewModel = wifiUiAdapter.bindGroup(mGroup, mLocation);
- }
-
- public boolean isDemoable() {
- return mDemoable;
- }
-
- public void setIsDemoable(boolean demoable) {
- mDemoable = demoable;
- }
-
- void setController(StatusBarIconController controller) {
- mController = controller;
- }
-
- public void setBlockList(@Nullable List<String> blockList) {
- Assert.isMainThread();
- mBlockList.clear();
- mBlockList.addAll(blockList);
- if (mController != null) {
- mController.refreshIconGroup(this);
- }
- }
-
- public void setShouldLog(boolean should) {
- mShouldLog = should;
- }
-
- public boolean shouldLog() {
- return mShouldLog;
- }
-
- protected void onIconAdded(int index, String slot, boolean blocked,
- StatusBarIconHolder holder) {
- addHolder(index, slot, blocked, holder);
- }
-
- protected StatusIconDisplayable addHolder(int index, String slot, boolean blocked,
- StatusBarIconHolder holder) {
- // This is a little hacky, and probably regrettable, but just set `blocked` on any icon
- // that is in our blocked list, then we'll never see it
- if (mBlockList.contains(slot)) {
- blocked = true;
- }
- switch (holder.getType()) {
- case TYPE_ICON:
- return addIcon(index, slot, blocked, holder.getIcon());
-
- case TYPE_WIFI_NEW:
- return addNewWifiIcon(index, slot);
-
- case TYPE_MOBILE_NEW:
- return addNewMobileIcon(index, slot, holder.getTag());
-
- case TYPE_BINDABLE:
- // Safe cast, since only BindableIconHolders can set this tag on themselves
- return addBindableIcon((BindableIconHolder) holder, index);
- }
-
- return null;
- }
-
- @VisibleForTesting
- protected StatusBarIconView addIcon(int index, String slot, boolean blocked,
- StatusBarIcon icon) {
- StatusBarIconView view = onCreateStatusBarIconView(slot, blocked);
- view.set(icon);
- mGroup.addView(view, index, onCreateLayoutParams());
- return view;
- }
-
- /**
- * ModernStatusBarViews can be created and bound, and thus do not need to update their
- * drawable by sending multiple calls to setIcon. Instead, by using a bindable
- * icon view, we can simply create the icon when requested and allow the
- * ViewBinder to control its visual state.
- */
- protected StatusIconDisplayable addBindableIcon(BindableIconHolder holder, int index) {
- ModernStatusBarView view = holder.getInitializer().createAndBind(mContext);
- mGroup.addView(view, index, onCreateLayoutParams());
- return view;
- }
-
- protected StatusIconDisplayable addNewWifiIcon(int index, String slot) {
- ModernStatusBarWifiView view = onCreateModernStatusBarWifiView(slot);
- mGroup.addView(view, index, onCreateLayoutParams());
-
- if (mIsInDemoMode) {
- mDemoStatusIcons.addModernWifiView(mWifiViewModel);
- }
-
- return view;
- }
-
-
- protected StatusIconDisplayable addNewMobileIcon(
- int index,
- String slot,
- int subId
- ) {
- BaseStatusBarFrameLayout view = onCreateModernStatusBarMobileView(slot, subId);
- mGroup.addView(view, index, onCreateLayoutParams());
-
- if (mIsInDemoMode) {
- Context mobileContext = mMobileContextProvider
- .getMobileContextForSub(subId, mContext);
- mDemoStatusIcons.addModernMobileView(
- mobileContext,
- mMobileIconsViewModel.getLogger(),
- subId);
- }
-
- return view;
- }
-
- private StatusBarIconView onCreateStatusBarIconView(String slot, boolean blocked) {
- return new StatusBarIconView(mContext, slot, null, blocked);
- }
-
- private ModernStatusBarWifiView onCreateModernStatusBarWifiView(String slot) {
- return ModernStatusBarWifiView.constructAndBind(mContext, slot, mWifiViewModel);
- }
-
- private ModernStatusBarMobileView onCreateModernStatusBarMobileView(
- String slot, int subId) {
- Context mobileContext = mMobileContextProvider.getMobileContextForSub(subId, mContext);
- return ModernStatusBarMobileView
- .constructAndBind(
- mobileContext,
- mMobileIconsViewModel.getLogger(),
- slot,
- mMobileIconsViewModel.viewModelForSub(subId, mLocation)
- );
- }
-
- protected LinearLayout.LayoutParams onCreateLayoutParams() {
- return new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, mIconSize);
- }
-
- protected void destroy() {
- mGroup.removeAllViews();
- }
-
- protected void reloadDimens() {
- mIconSize = mContext.getResources().getDimensionPixelSize(
- com.android.internal.R.dimen.status_bar_icon_size_sp);
- }
-
- protected void onRemoveIcon(int viewIndex) {
- if (mIsInDemoMode) {
- mDemoStatusIcons.onRemoveIcon((StatusIconDisplayable) mGroup.getChildAt(viewIndex));
- }
- mGroup.removeViewAt(viewIndex);
- }
-
- public void onSetIcon(int viewIndex, StatusBarIcon icon) {
- StatusBarIconView view = (StatusBarIconView) mGroup.getChildAt(viewIndex);
- view.set(icon);
- }
-
- public void onSetIconHolder(int viewIndex, StatusBarIconHolder holder) {
- switch (holder.getType()) {
- case TYPE_ICON:
- onSetIcon(viewIndex, holder.getIcon());
- return;
- case TYPE_MOBILE_NEW:
- case TYPE_WIFI_NEW:
- case TYPE_BINDABLE:
- // Nothing, the new icons update themselves
- return;
- default:
- break;
- }
- }
-
- @Override
- public void dispatchDemoCommand(String command, Bundle args) {
- if (!mDemoable) {
- return;
- }
-
- mDemoStatusIcons.dispatchDemoCommand(command, args);
- }
-
- @Override
- public void onDemoModeStarted() {
- mIsInDemoMode = true;
- if (mDemoStatusIcons == null) {
- mDemoStatusIcons = createDemoStatusIcons();
- mDemoStatusIcons.addModernWifiView(mWifiViewModel);
- }
- mDemoStatusIcons.onDemoModeStarted();
- }
-
- @Override
- public void onDemoModeFinished() {
- if (mDemoStatusIcons != null) {
- mDemoStatusIcons.onDemoModeFinished();
- exitDemoMode();
- mIsInDemoMode = false;
- }
- }
-
- protected void exitDemoMode() {
- mDemoStatusIcons.remove();
- mDemoStatusIcons = null;
- }
-
- protected DemoStatusIcons createDemoStatusIcons() {
- return new DemoStatusIcons(
- (LinearLayout) mGroup,
- mMobileIconsViewModel,
- mLocation,
- mIconSize
- );
- }
- }
-}
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 a141b53..f35d199 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -108,6 +108,10 @@
import kotlin.Unit;
+import kotlinx.coroutines.CoroutineDispatcher;
+import kotlinx.coroutines.ExperimentalCoroutinesApi;
+import kotlinx.coroutines.Job;
+
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashSet;
@@ -117,10 +121,6 @@
import javax.inject.Inject;
-import kotlinx.coroutines.CoroutineDispatcher;
-import kotlinx.coroutines.ExperimentalCoroutinesApi;
-import kotlinx.coroutines.Job;
-
/**
* Manages creating, showing, hiding and resetting the keyguard within the status bar. Calls back
* via {@link ViewMediatorCallback} to poke the wake lock and report that the keyguard is done,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
index 5d27467..e1a7f22 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
@@ -90,7 +90,6 @@
import javax.inject.Inject;
-
/**
* Status bar implementation of {@link NotificationActivityStarter}.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java
index 703b3c6..ba59398 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java
@@ -23,11 +23,12 @@
import android.util.Log;
import com.android.settingslib.mobile.TelephonyIcons;
-import com.android.systemui.res.R;
import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.res.R;
import com.android.systemui.statusbar.connectivity.IconState;
import com.android.systemui.statusbar.connectivity.NetworkController;
import com.android.systemui.statusbar.connectivity.SignalCallback;
+import com.android.systemui.statusbar.phone.ui.StatusBarIconController;
import com.android.systemui.statusbar.policy.SecurityController;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.tuner.TunerService.Tunable;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java
index 7910e6f..144939d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java
@@ -38,6 +38,7 @@
import com.android.systemui.statusbar.notification.stack.AnimationFilter;
import com.android.systemui.statusbar.notification.stack.AnimationProperties;
import com.android.systemui.statusbar.notification.stack.ViewState;
+import com.android.systemui.statusbar.phone.ui.StatusBarIconController;
import java.util.ArrayList;
import java.util.List;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SysuiDarkIconDispatcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SysuiDarkIconDispatcher.java
index 93db916..82f9eba 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SysuiDarkIconDispatcher.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SysuiDarkIconDispatcher.java
@@ -21,11 +21,11 @@
import com.android.systemui.Dumpable;
import com.android.systemui.plugins.DarkIconDispatcher;
+import kotlinx.coroutines.flow.StateFlow;
+
import java.util.ArrayList;
import java.util.Collection;
-import kotlinx.coroutines.flow.StateFlow;
-
/**
* Dispatches events to {@link DarkReceiver}s about changes in darkness, tint area
* and dark intensity.
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 c52132f..4fc11df 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
@@ -60,14 +60,14 @@
import com.android.systemui.statusbar.phone.NotificationIconContainer;
import com.android.systemui.statusbar.phone.PhoneStatusBarView;
import com.android.systemui.statusbar.phone.StatusBarHideIconsForBouncerManager;
-import com.android.systemui.statusbar.phone.StatusBarIconController;
-import com.android.systemui.statusbar.phone.StatusBarIconController.DarkIconManager;
import com.android.systemui.statusbar.phone.StatusBarLocation;
import com.android.systemui.statusbar.phone.StatusBarLocationPublisher;
import com.android.systemui.statusbar.phone.fragment.dagger.StatusBarFragmentComponent;
import com.android.systemui.statusbar.phone.fragment.dagger.StatusBarFragmentComponent.Startable;
import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController;
import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallListener;
+import com.android.systemui.statusbar.phone.ui.DarkIconManager;
+import com.android.systemui.statusbar.phone.ui.StatusBarIconController;
import com.android.systemui.statusbar.pipeline.shared.ui.binder.CollapsedStatusBarViewBinder;
import com.android.systemui.statusbar.pipeline.shared.ui.binder.StatusBarVisibilityChangeListener;
import com.android.systemui.statusbar.pipeline.shared.ui.viewmodel.CollapsedStatusBarViewModel;
@@ -79,8 +79,6 @@
import com.android.systemui.util.CarrierConfigTracker.DefaultDataSubscriptionChangedListener;
import com.android.systemui.util.settings.SecureSettings;
-import kotlin.Unit;
-
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
@@ -91,6 +89,8 @@
import javax.inject.Inject;
+import kotlin.Unit;
+
import kotlinx.coroutines.DisposableHandle;
/**
@@ -143,7 +143,7 @@
private final CollapsedStatusBarViewModel mCollapsedStatusBarViewModel;
private final CollapsedStatusBarViewBinder mCollapsedStatusBarViewBinder;
private final StatusBarHideIconsForBouncerManager mStatusBarHideIconsForBouncerManager;
- private final StatusBarIconController.DarkIconManager.Factory mDarkIconManagerFactory;
+ private final DarkIconManager.Factory mDarkIconManagerFactory;
private final SecureSettings mSecureSettings;
private final Executor mMainExecutor;
private final DumpManager mDumpManager;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ui/DarkIconManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ui/DarkIconManager.java
new file mode 100644
index 0000000..8871dae
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ui/DarkIconManager.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone.ui;
+
+import android.view.ViewGroup;
+import android.widget.LinearLayout;
+
+import com.android.internal.statusbar.StatusBarIcon;
+import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.plugins.DarkIconDispatcher;
+import com.android.systemui.statusbar.StatusIconDisplayable;
+import com.android.systemui.statusbar.connectivity.ui.MobileContextProvider;
+import com.android.systemui.statusbar.phone.DemoStatusIcons;
+import com.android.systemui.statusbar.phone.StatusBarIconHolder;
+import com.android.systemui.statusbar.phone.StatusBarLocation;
+import com.android.systemui.statusbar.pipeline.mobile.ui.MobileUiAdapter;
+import com.android.systemui.statusbar.pipeline.wifi.ui.WifiUiAdapter;
+
+import javax.inject.Inject;
+
+/**
+ * Version of {@link IconManager} that observes state from the DarkIconDispatcher.
+ */
+public class DarkIconManager extends IconManager {
+ private final DarkIconDispatcher mDarkIconDispatcher;
+ private final int mIconHorizontalMargin;
+
+ public DarkIconManager(
+ LinearLayout linearLayout,
+ StatusBarLocation location,
+ WifiUiAdapter wifiUiAdapter,
+ MobileUiAdapter mobileUiAdapter,
+ MobileContextProvider mobileContextProvider,
+ DarkIconDispatcher darkIconDispatcher) {
+ super(linearLayout,
+ location,
+ wifiUiAdapter,
+ mobileUiAdapter,
+ mobileContextProvider);
+ mIconHorizontalMargin = mContext.getResources().getDimensionPixelSize(
+ com.android.systemui.res.R.dimen.status_bar_icon_horizontal_margin);
+ mDarkIconDispatcher = darkIconDispatcher;
+ }
+
+ @Override
+ protected void onIconAdded(int index, String slot, boolean blocked,
+ StatusBarIconHolder holder) {
+ StatusIconDisplayable view = addHolder(index, slot, blocked, holder);
+ mDarkIconDispatcher.addDarkReceiver(view);
+ }
+
+ @Override
+ protected LinearLayout.LayoutParams onCreateLayoutParams() {
+ LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
+ ViewGroup.LayoutParams.WRAP_CONTENT, mIconSize);
+ lp.setMargins(mIconHorizontalMargin, 0, mIconHorizontalMargin, 0);
+ return lp;
+ }
+
+ @Override
+ protected void destroy() {
+ for (int i = 0; i < mGroup.getChildCount(); i++) {
+ mDarkIconDispatcher.removeDarkReceiver(
+ (DarkIconDispatcher.DarkReceiver) mGroup.getChildAt(i));
+ }
+ mGroup.removeAllViews();
+ }
+
+ @Override
+ protected void onRemoveIcon(int viewIndex) {
+ mDarkIconDispatcher.removeDarkReceiver(
+ (DarkIconDispatcher.DarkReceiver) mGroup.getChildAt(viewIndex));
+ super.onRemoveIcon(viewIndex);
+ }
+
+ @Override
+ public void onSetIcon(int viewIndex, StatusBarIcon icon) {
+ super.onSetIcon(viewIndex, icon);
+ mDarkIconDispatcher.applyDark(
+ (DarkIconDispatcher.DarkReceiver) mGroup.getChildAt(viewIndex));
+ }
+
+ @Override
+ protected DemoStatusIcons createDemoStatusIcons() {
+ DemoStatusIcons icons = super.createDemoStatusIcons();
+ mDarkIconDispatcher.addDarkReceiver(icons);
+
+ return icons;
+ }
+
+ @Override
+ protected void exitDemoMode() {
+ mDarkIconDispatcher.removeDarkReceiver(mDemoStatusIcons);
+ super.exitDemoMode();
+ }
+
+ @SysUISingleton
+ public static class Factory {
+ private final WifiUiAdapter mWifiUiAdapter;
+ private final MobileContextProvider mMobileContextProvider;
+ private final MobileUiAdapter mMobileUiAdapter;
+ private final DarkIconDispatcher mDarkIconDispatcher;
+
+ @Inject
+ public Factory(
+ WifiUiAdapter wifiUiAdapter,
+ MobileContextProvider mobileContextProvider,
+ MobileUiAdapter mobileUiAdapter,
+ DarkIconDispatcher darkIconDispatcher) {
+ mWifiUiAdapter = wifiUiAdapter;
+ mMobileContextProvider = mobileContextProvider;
+ mMobileUiAdapter = mobileUiAdapter;
+ mDarkIconDispatcher = darkIconDispatcher;
+ }
+
+ /** Creates a new {@link DarkIconManager} for the given view group and location. */
+ public DarkIconManager create(LinearLayout group, StatusBarLocation location) {
+ return new DarkIconManager(
+ group,
+ location,
+ mWifiUiAdapter,
+ mMobileUiAdapter,
+ mMobileContextProvider,
+ mDarkIconDispatcher);
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ui/IconManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ui/IconManager.java
new file mode 100644
index 0000000..0ed9420
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ui/IconManager.java
@@ -0,0 +1,307 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone.ui;
+
+import static com.android.systemui.statusbar.phone.StatusBarIconHolder.TYPE_BINDABLE;
+import static com.android.systemui.statusbar.phone.StatusBarIconHolder.TYPE_ICON;
+import static com.android.systemui.statusbar.phone.StatusBarIconHolder.TYPE_MOBILE_NEW;
+import static com.android.systemui.statusbar.phone.StatusBarIconHolder.TYPE_WIFI_NEW;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.os.Bundle;
+import android.view.ViewGroup;
+import android.widget.LinearLayout;
+
+import androidx.annotation.VisibleForTesting;
+
+import com.android.internal.statusbar.StatusBarIcon;
+import com.android.systemui.demomode.DemoModeCommandReceiver;
+import com.android.systemui.statusbar.BaseStatusBarFrameLayout;
+import com.android.systemui.statusbar.StatusBarIconView;
+import com.android.systemui.statusbar.StatusIconDisplayable;
+import com.android.systemui.statusbar.connectivity.ui.MobileContextProvider;
+import com.android.systemui.statusbar.phone.DemoStatusIcons;
+import com.android.systemui.statusbar.phone.StatusBarIconHolder;
+import com.android.systemui.statusbar.phone.StatusBarLocation;
+import com.android.systemui.statusbar.pipeline.mobile.ui.MobileUiAdapter;
+import com.android.systemui.statusbar.pipeline.mobile.ui.binder.MobileIconsBinder;
+import com.android.systemui.statusbar.pipeline.mobile.ui.view.ModernStatusBarMobileView;
+import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconsViewModel;
+import com.android.systemui.statusbar.pipeline.shared.ui.view.ModernStatusBarView;
+import com.android.systemui.statusbar.pipeline.wifi.ui.WifiUiAdapter;
+import com.android.systemui.statusbar.pipeline.wifi.ui.view.ModernStatusBarWifiView;
+import com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel.LocationBasedWifiViewModel;
+import com.android.systemui.util.Assert;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Turns info from StatusBarIconController into ImageViews in a ViewGroup.
+ */
+public class IconManager implements DemoModeCommandReceiver {
+ protected final ViewGroup mGroup;
+ private final MobileContextProvider mMobileContextProvider;
+ private final LocationBasedWifiViewModel mWifiViewModel;
+ private final MobileIconsViewModel mMobileIconsViewModel;
+
+ protected final Context mContext;
+ protected int mIconSize;
+ // Whether or not these icons show up in dumpsys
+ protected boolean mShouldLog = false;
+ private StatusBarIconController mController;
+ private final StatusBarLocation mLocation;
+
+ // Enables SystemUI demo mode to take effect in this group
+ protected boolean mDemoable = true;
+ private boolean mIsInDemoMode;
+ protected DemoStatusIcons mDemoStatusIcons;
+
+ protected ArrayList<String> mBlockList = new ArrayList<>();
+
+ public IconManager(
+ ViewGroup group,
+ StatusBarLocation location,
+ WifiUiAdapter wifiUiAdapter,
+ MobileUiAdapter mobileUiAdapter,
+ MobileContextProvider mobileContextProvider
+ ) {
+ mGroup = group;
+ mMobileContextProvider = mobileContextProvider;
+ mContext = group.getContext();
+ mLocation = location;
+
+ reloadDimens();
+
+ // This starts the flow for the new pipeline, and will notify us of changes via
+ // {@link #setNewMobileIconIds}
+ mMobileIconsViewModel = mobileUiAdapter.getMobileIconsViewModel();
+ MobileIconsBinder.bind(mGroup, mMobileIconsViewModel);
+
+ mWifiViewModel = wifiUiAdapter.bindGroup(mGroup, mLocation);
+ }
+
+ public boolean isDemoable() {
+ return mDemoable;
+ }
+
+ void setController(StatusBarIconController controller) {
+ mController = controller;
+ }
+
+ /** Sets the list of slots that should be blocked from showing in the status bar. */
+ public void setBlockList(@Nullable List<String> blockList) {
+ Assert.isMainThread();
+ mBlockList.clear();
+ mBlockList.addAll(blockList);
+ if (mController != null) {
+ mController.refreshIconGroup(this);
+ }
+ }
+
+ /** Sets whether this manager's changes should be dumped in a bug report. */
+ public void setShouldLog(boolean should) {
+ mShouldLog = should;
+ }
+
+ /** Returns true if this manager's changes should be dumped in a bug report. */
+ public boolean shouldLog() {
+ return mShouldLog;
+ }
+
+ protected void onIconAdded(int index, String slot, boolean blocked,
+ StatusBarIconHolder holder) {
+ addHolder(index, slot, blocked, holder);
+ }
+
+ protected StatusIconDisplayable addHolder(int index, String slot, boolean blocked,
+ StatusBarIconHolder holder) {
+ // This is a little hacky, and probably regrettable, but just set `blocked` on any icon
+ // that is in our blocked list, then we'll never see it
+ if (mBlockList.contains(slot)) {
+ blocked = true;
+ }
+ return switch (holder.getType()) {
+ case TYPE_ICON -> addIcon(index, slot, blocked, holder.getIcon());
+ case TYPE_WIFI_NEW -> addNewWifiIcon(index, slot);
+ case TYPE_MOBILE_NEW -> addNewMobileIcon(index, slot, holder.getTag());
+ case TYPE_BINDABLE ->
+ // Safe cast, since only BindableIconHolders can set this tag on themselves
+ addBindableIcon((StatusBarIconHolder.BindableIconHolder) holder, index);
+ default -> null;
+ };
+ }
+
+ @VisibleForTesting
+ protected StatusBarIconView addIcon(int index, String slot, boolean blocked,
+ StatusBarIcon icon) {
+ StatusBarIconView view = onCreateStatusBarIconView(slot, blocked);
+ view.set(icon);
+ mGroup.addView(view, index, onCreateLayoutParams());
+ return view;
+ }
+
+ /**
+ * ModernStatusBarViews can be created and bound, and thus do not need to update their
+ * drawable by sending multiple calls to setIcon. Instead, by using a bindable
+ * icon view, we can simply create the icon when requested and allow the
+ * ViewBinder to control its visual state.
+ */
+ protected StatusIconDisplayable addBindableIcon(StatusBarIconHolder.BindableIconHolder holder,
+ int index) {
+ ModernStatusBarView view = holder.getInitializer().createAndBind(mContext);
+ mGroup.addView(view, index, onCreateLayoutParams());
+ return view;
+ }
+
+ protected StatusIconDisplayable addNewWifiIcon(int index, String slot) {
+ ModernStatusBarWifiView view = onCreateModernStatusBarWifiView(slot);
+ mGroup.addView(view, index, onCreateLayoutParams());
+
+ if (mIsInDemoMode) {
+ mDemoStatusIcons.addModernWifiView(mWifiViewModel);
+ }
+
+ return view;
+ }
+
+
+ protected StatusIconDisplayable addNewMobileIcon(
+ int index,
+ String slot,
+ int subId
+ ) {
+ BaseStatusBarFrameLayout view = onCreateModernStatusBarMobileView(slot, subId);
+ mGroup.addView(view, index, onCreateLayoutParams());
+
+ if (mIsInDemoMode) {
+ Context mobileContext = mMobileContextProvider
+ .getMobileContextForSub(subId, mContext);
+ mDemoStatusIcons.addModernMobileView(
+ mobileContext,
+ mMobileIconsViewModel.getLogger(),
+ subId);
+ }
+
+ return view;
+ }
+
+ private StatusBarIconView onCreateStatusBarIconView(String slot, boolean blocked) {
+ return new StatusBarIconView(mContext, slot, null, blocked);
+ }
+
+ private ModernStatusBarWifiView onCreateModernStatusBarWifiView(String slot) {
+ return ModernStatusBarWifiView.constructAndBind(mContext, slot, mWifiViewModel);
+ }
+
+ private ModernStatusBarMobileView onCreateModernStatusBarMobileView(
+ String slot, int subId) {
+ Context mobileContext = mMobileContextProvider.getMobileContextForSub(subId, mContext);
+ return ModernStatusBarMobileView
+ .constructAndBind(
+ mobileContext,
+ mMobileIconsViewModel.getLogger(),
+ slot,
+ mMobileIconsViewModel.viewModelForSub(subId, mLocation)
+ );
+ }
+
+ protected LinearLayout.LayoutParams onCreateLayoutParams() {
+ return new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, mIconSize);
+ }
+
+ protected void destroy() {
+ mGroup.removeAllViews();
+ }
+
+ protected void reloadDimens() {
+ mIconSize = mContext.getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.status_bar_icon_size_sp);
+ }
+
+ protected void onRemoveIcon(int viewIndex) {
+ if (mIsInDemoMode) {
+ mDemoStatusIcons.onRemoveIcon((StatusIconDisplayable) mGroup.getChildAt(viewIndex));
+ }
+ mGroup.removeViewAt(viewIndex);
+ }
+
+ /** Called once an icon has been set. */
+ public void onSetIcon(int viewIndex, StatusBarIcon icon) {
+ StatusBarIconView view = (StatusBarIconView) mGroup.getChildAt(viewIndex);
+ view.set(icon);
+ }
+
+ /** Called once an icon holder has been set. */
+ public void onSetIconHolder(int viewIndex, StatusBarIconHolder holder) {
+ switch (holder.getType()) {
+ case TYPE_ICON:
+ onSetIcon(viewIndex, holder.getIcon());
+ return;
+ case TYPE_MOBILE_NEW:
+ case TYPE_WIFI_NEW:
+ case TYPE_BINDABLE:
+ // Nothing, the new icons update themselves
+ return;
+ default:
+ break;
+ }
+ }
+
+ @Override
+ public void dispatchDemoCommand(String command, Bundle args) {
+ if (!mDemoable) {
+ return;
+ }
+
+ mDemoStatusIcons.dispatchDemoCommand(command, args);
+ }
+
+ @Override
+ public void onDemoModeStarted() {
+ mIsInDemoMode = true;
+ if (mDemoStatusIcons == null) {
+ mDemoStatusIcons = createDemoStatusIcons();
+ mDemoStatusIcons.addModernWifiView(mWifiViewModel);
+ }
+ mDemoStatusIcons.onDemoModeStarted();
+ }
+
+ @Override
+ public void onDemoModeFinished() {
+ if (mDemoStatusIcons != null) {
+ mDemoStatusIcons.onDemoModeFinished();
+ exitDemoMode();
+ mIsInDemoMode = false;
+ }
+ }
+
+ protected void exitDemoMode() {
+ mDemoStatusIcons.remove();
+ mDemoStatusIcons = null;
+ }
+
+ protected DemoStatusIcons createDemoStatusIcons() {
+ return new DemoStatusIcons(
+ (LinearLayout) mGroup,
+ mMobileIconsViewModel,
+ mLocation,
+ mIconSize
+ );
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ui/StatusBarIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ui/StatusBarIconController.java
new file mode 100644
index 0000000..1ada30e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ui/StatusBarIconController.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone.ui;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.text.TextUtils;
+import android.util.ArraySet;
+
+import com.android.internal.statusbar.StatusBarIcon;
+import com.android.systemui.res.R;
+import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.CallIndicatorIconState;
+
+import java.util.List;
+
+/** Interface controlling the icons shown in the status bar. */
+public interface StatusBarIconController {
+
+ /**
+ * When an icon is added with TAG_PRIMARY, it will be treated as the primary icon
+ * in that slot and not added as a sub slot.
+ */
+ int TAG_PRIMARY = 0;
+
+ /** */
+ void addIconGroup(IconManager iconManager);
+ /** */
+ void removeIconGroup(IconManager iconManager);
+
+ /** Refresh the state of an IconManager by recreating the views */
+ void refreshIconGroup(IconManager iconManager);
+
+ /**
+ * Adds or updates an icon that comes from an active tile service.
+ *
+ * If the icon is null, the icon will be removed.
+ */
+ void setIconFromTile(String slot, @Nullable StatusBarIcon icon);
+
+ /** Removes an icon that had come from an active tile service. */
+ void removeIconForTile(String slot);
+
+ /** Adds or updates an icon for the given slot for **internal system icons**. */
+ void setIcon(String slot, int resourceId, CharSequence contentDescription);
+
+ /**
+ * Sets up a wifi icon using the new data pipeline. No effect if the wifi icon has already been
+ * set up (inflated and added to the view hierarchy).
+ */
+ void setNewWifiIcon();
+
+ /**
+ * Notify this class that there is a new set of mobile icons to display, keyed off of this list
+ * of subIds. The icons will be added and bound to the mobile data pipeline via
+ * {@link com.android.systemui.statusbar.pipeline.mobile.ui.binder.MobileIconBinder}.
+ */
+ void setNewMobileIconSubIds(List<Integer> subIds);
+ /**
+ * Display the no calling & SMS icons.
+ */
+ void setCallStrengthIcons(String slot, List<CallIndicatorIconState> states);
+
+ /**
+ * Display the no calling & SMS icons.
+ */
+ void setNoCallingIcons(String slot, List<CallIndicatorIconState> states);
+
+ /** Sets whether the icon in the given slot should be visible or not. */
+ void setIconVisibility(String slot, boolean b);
+
+ /**
+ * Sets the live region mode for the icon
+ *
+ * @param slot Icon slot to set region for
+ * @param accessibilityLiveRegion live region mode for the icon
+ * @see android.view.View#setAccessibilityLiveRegion(int)
+ */
+ void setIconAccessibilityLiveRegion(String slot, int accessibilityLiveRegion);
+
+ /**
+ * If you don't know what to pass for `tag`, either remove all icons for slot, or use
+ * TAG_PRIMARY to refer to the first icon at a given slot.
+ */
+ void removeIcon(String slot, int tag);
+
+ // TODO: See if we can rename this tunable name.
+ String ICON_HIDE_LIST = "icon_blacklist";
+
+ /** Reads the default hide list from config value unless hideListStr is provided. */
+ static ArraySet<String> getIconHideList(Context context, String hideListStr) {
+ ArraySet<String> ret = new ArraySet<>();
+ String[] hideList = hideListStr == null
+ ? context.getResources().getStringArray(R.array.config_statusBarIconsToExclude)
+ : hideListStr.split(",");
+ for (String slot : hideList) {
+ if (!TextUtils.isEmpty(slot)) {
+ ret.add(slot);
+ }
+ }
+ return ret;
+ }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ui/StatusBarIconControllerImpl.java
similarity index 97%
rename from packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/phone/ui/StatusBarIconControllerImpl.java
index 4f148f1..92d90af 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ui/StatusBarIconControllerImpl.java
@@ -11,12 +11,12 @@
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
- * limitations under the License
+ * limitations under the License.
*/
-package com.android.systemui.statusbar.phone;
+package com.android.systemui.statusbar.phone.ui;
-import static com.android.systemui.statusbar.phone.StatusBarIconList.Slot;
+import static com.android.systemui.statusbar.phone.ui.StatusBarIconList.Slot;
import android.annotation.NonNull;
import android.content.Context;
@@ -38,6 +38,7 @@
import com.android.systemui.dump.DumpManager;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.StatusIconDisplayable;
+import com.android.systemui.statusbar.phone.StatusBarIconHolder;
import com.android.systemui.statusbar.phone.StatusBarIconHolder.BindableIconHolder;
import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.CallIndicatorIconState;
import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags;
@@ -459,9 +460,9 @@
for (IconManager manager : mIconGroups) {
if (manager.shouldLog()) {
ViewGroup group = manager.mGroup;
- int N = group.getChildCount();
- pw.println(" icon views: " + N);
- for (int i = 0; i < N; i++) {
+ int n = group.getChildCount();
+ pw.println(" icon views: " + n);
+ for (int i = 0; i < n; i++) {
StatusIconDisplayable ic = (StatusIconDisplayable) group.getChildAt(i);
pw.println(" [" + i + "] icon=" + ic);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconList.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ui/StatusBarIconList.java
similarity index 97%
rename from packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconList.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/phone/ui/StatusBarIconList.java
index 565481a..724251c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconList.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ui/StatusBarIconList.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015 The Android Open Source Project
+ * Copyright (C) 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,14 +14,15 @@
* limitations under the License.
*/
-package com.android.systemui.statusbar.phone;
+package com.android.systemui.statusbar.phone.ui;
-import static com.android.systemui.statusbar.phone.StatusBarIconController.TAG_PRIMARY;
+import static com.android.systemui.statusbar.phone.ui.StatusBarIconController.TAG_PRIMARY;
import android.annotation.NonNull;
import android.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.statusbar.phone.StatusBarIconHolder;
import java.io.PrintWriter;
import java.util.ArrayList;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ui/TintedIconManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ui/TintedIconManager.java
new file mode 100644
index 0000000..e520148
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ui/TintedIconManager.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone.ui;
+
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.statusbar.StatusIconDisplayable;
+import com.android.systemui.statusbar.connectivity.ui.MobileContextProvider;
+import com.android.systemui.statusbar.phone.DemoStatusIcons;
+import com.android.systemui.statusbar.phone.StatusBarIconHolder;
+import com.android.systemui.statusbar.phone.StatusBarLocation;
+import com.android.systemui.statusbar.pipeline.mobile.ui.MobileUiAdapter;
+import com.android.systemui.statusbar.pipeline.wifi.ui.WifiUiAdapter;
+
+import javax.inject.Inject;
+
+/**
+ * Version of {@link IconManager} that can tint the icons to a particular color.
+ */
+public class TintedIconManager extends IconManager {
+ // The main tint, used as the foreground in non layer drawables
+ private int mColor;
+ // To be used as the main tint in drawables that wish to have a layer
+ private int mForegroundColor;
+
+ public TintedIconManager(
+ ViewGroup group,
+ StatusBarLocation location,
+ WifiUiAdapter wifiUiAdapter,
+ MobileUiAdapter mobileUiAdapter,
+ MobileContextProvider mobileContextProvider
+ ) {
+ super(group,
+ location,
+ wifiUiAdapter,
+ mobileUiAdapter,
+ mobileContextProvider);
+ }
+
+ @Override
+ protected void onIconAdded(int index, String slot, boolean blocked,
+ StatusBarIconHolder holder) {
+ StatusIconDisplayable view = addHolder(index, slot, blocked, holder);
+ view.setStaticDrawableColor(mColor, mForegroundColor);
+ view.setDecorColor(mColor);
+ }
+
+ /**
+ * Most icons are a single layer, and tintColor will be used as the tint in those cases.
+ * For icons that have a background, foregroundColor becomes the contrasting tint used
+ * for the foreground.
+ *
+ * @param tintColor the main tint to use for the icons in the group
+ * @param foregroundColor used as the main tint for layer-ish drawables where tintColor is
+ * being used as the background
+ */
+ public void setTint(int tintColor, int foregroundColor) {
+ mColor = tintColor;
+ mForegroundColor = foregroundColor;
+
+ for (int i = 0; i < mGroup.getChildCount(); i++) {
+ View child = mGroup.getChildAt(i);
+ if (child instanceof StatusIconDisplayable icon) {
+ icon.setStaticDrawableColor(mColor, mForegroundColor);
+ icon.setDecorColor(mColor);
+ }
+ }
+
+ if (mDemoStatusIcons != null) {
+ mDemoStatusIcons.setColor(tintColor, foregroundColor);
+ }
+ }
+
+ @Override
+ protected DemoStatusIcons createDemoStatusIcons() {
+ DemoStatusIcons icons = super.createDemoStatusIcons();
+ icons.setColor(mColor, mForegroundColor);
+ return icons;
+ }
+
+ @SysUISingleton
+ public static class Factory {
+ private final WifiUiAdapter mWifiUiAdapter;
+ private final MobileContextProvider mMobileContextProvider;
+ private final MobileUiAdapter mMobileUiAdapter;
+
+ @Inject
+ public Factory(
+ WifiUiAdapter wifiUiAdapter,
+ MobileUiAdapter mobileUiAdapter,
+ MobileContextProvider mobileContextProvider
+ ) {
+ mWifiUiAdapter = wifiUiAdapter;
+ mMobileUiAdapter = mobileUiAdapter;
+ mMobileContextProvider = mobileContextProvider;
+ }
+
+ /** Creates a new {@link TintedIconManager} for the given view group and location. */
+ public TintedIconManager create(ViewGroup group, StatusBarLocation location) {
+ return new TintedIconManager(
+ group,
+ location,
+ mWifiUiAdapter,
+ mMobileUiAdapter,
+ mMobileContextProvider);
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileUiAdapter.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileUiAdapter.kt
index 02e50a0..5a49f8e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileUiAdapter.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileUiAdapter.kt
@@ -20,7 +20,7 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.shade.carrier.ShadeCarrierGroupController
-import com.android.systemui.statusbar.phone.StatusBarIconController
+import com.android.systemui.statusbar.phone.ui.StatusBarIconController
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractor
import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconsViewModel
import java.io.PrintWriter
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/MobileIconsBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/MobileIconsBinder.kt
index e7d5ee2..fc0ba13 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/MobileIconsBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/MobileIconsBinder.kt
@@ -20,10 +20,9 @@
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
import com.android.systemui.lifecycle.repeatWhenAttached
-import com.android.systemui.statusbar.phone.StatusBarIconController.IconManager
+import com.android.systemui.statusbar.phone.ui.IconManager
import com.android.systemui.statusbar.pipeline.mobile.ui.MobileUiAdapter
import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconsViewModel
-import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
object MobileIconsBinder {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/data/repository/ConnectivityRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/data/repository/ConnectivityRepository.kt
index 4227f9e..1a55f7d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/data/repository/ConnectivityRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/data/repository/ConnectivityRepository.kt
@@ -31,12 +31,12 @@
import androidx.annotation.ArrayRes
import androidx.annotation.VisibleForTesting
import com.android.systemui.Dumpable
-import com.android.systemui.res.R
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dump.DumpManager
-import com.android.systemui.statusbar.phone.StatusBarIconController
+import com.android.systemui.res.R
+import com.android.systemui.statusbar.phone.ui.StatusBarIconController
import com.android.systemui.statusbar.pipeline.shared.ConnectivityInputLogger
import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlot
import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlots
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt
index 20e44e7..885abca 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt
@@ -322,11 +322,6 @@
wifiManager.registerTrafficStateCallback(mainExecutor, callback)
awaitClose { wifiManager.unregisterTrafficStateCallback(callback) }
}
- .logDiffsForTable(
- tableLogger,
- columnPrefix = ACTIVITY_PREFIX,
- initialValue = ACTIVITY_DEFAULT,
- )
.stateIn(
scope,
started = SharingStarted.WhileSubscribed(),
@@ -441,7 +436,6 @@
private const val WIFI_STATE_DEFAULT = WifiManager.WIFI_STATE_DISABLED
- private const val ACTIVITY_PREFIX = "wifiActivity"
val ACTIVITY_DEFAULT = DataActivityModel(hasActivityIn = false, hasActivityOut = false)
private const val TAG = "WifiTrackerLibInputLog"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/WifiUiAdapter.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/WifiUiAdapter.kt
index 7a60d96..2800c94 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/WifiUiAdapter.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/WifiUiAdapter.kt
@@ -21,14 +21,13 @@
import androidx.lifecycle.repeatOnLifecycle
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.lifecycle.repeatWhenAttached
-import com.android.systemui.statusbar.phone.StatusBarIconController
import com.android.systemui.statusbar.phone.StatusBarLocation
+import com.android.systemui.statusbar.phone.ui.StatusBarIconController
import com.android.systemui.statusbar.pipeline.wifi.ui.model.WifiIcon
import com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel.LocationBasedWifiViewModel
import com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel.LocationBasedWifiViewModel.Companion.viewModelForLocation
import com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel.WifiViewModel
import javax.inject.Inject
-import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AvalancheController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AvalancheController.kt
index 36c23d3..2670a95 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AvalancheController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AvalancheController.kt
@@ -40,6 +40,9 @@
// HUN showing right now, in the floating state where full shade is hidden, on launcher or AOD
@VisibleForTesting var headsUpEntryShowing: HeadsUpEntry? = null
+ // Key of HUN previously showing, is being removed or was removed
+ var previousHunKey: String = ""
+
// List of runnables to run for the HUN showing right now
private var headsUpEntryShowingRunnableList: MutableList<Runnable> = ArrayList()
@@ -63,6 +66,10 @@
dumpManager.registerNormalDumpable(tag, /* module */ this)
}
+ fun getShowingHunKey(): String {
+ return getKey(headsUpEntryShowing)
+ }
+
/** Run or delay Runnable for given HeadsUpEntry */
fun update(entry: HeadsUpEntry?, runnable: Runnable, label: String) {
if (!NotificationThrottleHun.isEnabled) {
@@ -134,8 +141,10 @@
debugDropSet.remove(entry)
} else if (isShowing(entry)) {
log { "$fn => [remove showing ${getKey(entry)}]" }
+ previousHunKey = getKey(headsUpEntryShowing)
+
runnable.run()
- showNext()
+ showNextAfterRemove()
} else {
log { "$fn => [removing untracked ${getKey(entry)}]" }
}
@@ -238,7 +247,7 @@
}
}
- private fun showNext() {
+ private fun showNextAfterRemove() {
log { "SHOW NEXT" }
headsUpEntryShowing = null
@@ -284,6 +293,7 @@
private fun getStateStr(): String {
return "SHOWING: [${getKey(headsUpEntryShowing)}]" +
+ "\nPREVIOUS: [$previousHunKey]" +
"\nNEXT LIST: $nextListStr" +
"\nNEXT MAP: $nextMapStr" +
"\nDROPPED: $dropSetStr"
@@ -325,10 +335,10 @@
fun getKey(entry: HeadsUpEntry?): String {
if (entry == null) {
- return "null"
+ return "HeadsUpEntry null"
}
if (entry.mEntry == null) {
- return entry.toString()
+ return "HeadsUpEntry.mEntry null"
}
return entry.mEntry!!.key
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastControllerImpl.java
index 149c8fa..64bdf60 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastControllerImpl.java
@@ -48,7 +48,6 @@
import javax.inject.Inject;
-
/** Platform implementation of the cast controller. **/
@SysUISingleton
public class CastControllerImpl implements CastController {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
index 20d1fff..ccd7560 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
@@ -48,14 +48,14 @@
import com.android.settingslib.Utils;
import com.android.systemui.Dependency;
import com.android.systemui.FontSizeUtils;
-import com.android.systemui.res.R;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.demomode.DemoModeCommandReceiver;
import com.android.systemui.plugins.DarkIconDispatcher;
import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
+import com.android.systemui.res.R;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.phone.StatusBarIconController;
+import com.android.systemui.statusbar.phone.ui.StatusBarIconController;
import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.tuner.TunerService.Tunable;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DateView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DateView.java
index 74e02d7..7e6e00e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DateView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DateView.java
@@ -29,8 +29,8 @@
import android.widget.TextView;
import com.android.systemui.Dependency;
-import com.android.systemui.res.R;
import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.res.R;
import java.util.Date;
import java.util.Locale;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
index 4b97197..d0cc32b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
@@ -32,11 +32,11 @@
import androidx.annotation.NonNull;
import com.android.internal.util.ConcurrentUtils;
-import com.android.systemui.res.R;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.res.R;
import com.android.systemui.settings.UserTracker;
import java.io.PrintWriter;
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 ad2b070..b07aa81 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateController.java
@@ -18,7 +18,6 @@
import android.app.IActivityTaskManager;
-import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.policy.KeyguardStateController.Callback;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserDetailItemView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserDetailItemView.java
index 012408e..3eeb59d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserDetailItemView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserDetailItemView.java
@@ -26,8 +26,8 @@
import com.android.app.animation.Interpolators;
import com.android.keyguard.KeyguardConstants;
-import com.android.systemui.res.R;
import com.android.systemui.qs.tiles.UserDetailItemView;
+import com.android.systemui.res.R;
/**
* Displays a user on the keyguard user switcher.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyConstants.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyConstants.java
index bf33473..8daa518 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyConstants.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyConstants.java
@@ -19,16 +19,15 @@
import android.app.RemoteInput;
import android.content.Context;
import android.content.res.Resources;
-import android.os.Handler;
import android.provider.DeviceConfig;
import android.text.TextUtils;
import android.util.KeyValueListParser;
import android.util.Log;
import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
-import com.android.systemui.res.R;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.res.R;
import com.android.systemui.util.DeviceConfigProxy;
import java.util.concurrent.Executor;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoControllerImpl.java
index 2ed9d15..712bab0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoControllerImpl.java
@@ -36,9 +36,9 @@
import com.android.internal.util.UserIcons;
import com.android.settingslib.drawable.UserIconDrawable;
-import com.android.systemui.res.R;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.res.R;
import com.android.systemui.settings.UserTracker;
import java.util.ArrayList;
diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeModule.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeModule.java
index e78eba4..0cd917f 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/ThemeModule.java
+++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeModule.java
@@ -18,15 +18,15 @@
import android.content.res.Resources;
-import com.android.systemui.res.R;
import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.res.R;
import com.android.systemui.util.concurrency.SysUIConcurrencyModule;
-import javax.inject.Named;
-
import dagger.Module;
import dagger.Provides;
+import javax.inject.Named;
+
/** */
@Module(includes = {SysUIConcurrencyModule.class})
public class ThemeModule {
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/BatteryPreference.java b/packages/SystemUI/src/com/android/systemui/tuner/BatteryPreference.java
index b71aafd..77fcd25 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/BatteryPreference.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/BatteryPreference.java
@@ -27,7 +27,7 @@
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.systemui.Dependency;
-import com.android.systemui.statusbar.phone.StatusBarIconController;
+import com.android.systemui.statusbar.phone.ui.StatusBarIconController;
public class BatteryPreference extends DropDownPreference implements TunerService.Tunable {
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/ClockPreference.java b/packages/SystemUI/src/com/android/systemui/tuner/ClockPreference.java
index c92d7bb..e94d8ea 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/ClockPreference.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/ClockPreference.java
@@ -21,7 +21,7 @@
import androidx.preference.DropDownPreference;
import com.android.systemui.Dependency;
-import com.android.systemui.statusbar.phone.StatusBarIconController;
+import com.android.systemui.statusbar.phone.ui.StatusBarIconController;
import com.android.systemui.statusbar.policy.Clock;
public class ClockPreference extends DropDownPreference implements TunerService.Tunable {
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/DemoModeFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/DemoModeFragment.java
index a43524a..68918ef 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/DemoModeFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/DemoModeFragment.java
@@ -29,10 +29,10 @@
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.systemui.res.R;
import com.android.systemui.demomode.DemoMode;
import com.android.systemui.demomode.DemoModeAvailabilityTracker;
import com.android.systemui.demomode.DemoModeController;
+import com.android.systemui.res.R;
import com.android.systemui.util.settings.GlobalSettings;
public class DemoModeFragment extends PreferenceFragment implements OnPreferenceChangeListener {
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/LockscreenFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/LockscreenFragment.java
index 799e5af..ab2a7c7 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/LockscreenFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/LockscreenFragment.java
@@ -41,8 +41,8 @@
import androidx.recyclerview.widget.RecyclerView.ViewHolder;
import com.android.systemui.Dependency;
-import com.android.systemui.res.R;
import com.android.systemui.plugins.IntentButtonProvider.IntentButton;
+import com.android.systemui.res.R;
import com.android.systemui.statusbar.ScalingDrawableWrapper;
import com.android.systemui.statusbar.phone.ExpandableIndicator;
import com.android.systemui.statusbar.policy.ExtensionController.TunerFactory;
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/PluginFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/PluginFragment.java
index 7635a84..c7b848c 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/PluginFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/PluginFragment.java
@@ -36,9 +36,9 @@
import com.android.internal.util.ArrayUtils;
import com.android.systemui.Dependency;
-import com.android.systemui.res.R;
import com.android.systemui.plugins.PluginEnablerImpl;
import com.android.systemui.plugins.PluginManager;
+import com.android.systemui.res.R;
import com.android.systemui.shared.plugins.PluginActionManager;
import com.android.systemui.shared.plugins.PluginEnabler;
import com.android.systemui.shared.plugins.PluginPrefs;
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/RadioListPreference.java b/packages/SystemUI/src/com/android/systemui/tuner/RadioListPreference.java
index 20ce230..50ed3ef 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/RadioListPreference.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/RadioListPreference.java
@@ -29,8 +29,8 @@
import com.android.settingslib.Utils;
import com.android.systemui.Dependency;
-import com.android.systemui.res.R;
import com.android.systemui.fragments.FragmentService;
+import com.android.systemui.res.R;
import java.util.Objects;
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/StatusBarSwitch.java b/packages/SystemUI/src/com/android/systemui/tuner/StatusBarSwitch.java
index cc0050b..2f6fa51 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/StatusBarSwitch.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/StatusBarSwitch.java
@@ -27,7 +27,7 @@
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.systemui.Dependency;
-import com.android.systemui.statusbar.phone.StatusBarIconController;
+import com.android.systemui.statusbar.phone.ui.StatusBarIconController;
import com.android.systemui.tuner.TunerService.Tunable;
import java.util.Set;
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerActivity.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerActivity.java
index 14d7281..2135817 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerActivity.java
@@ -30,9 +30,9 @@
import androidx.preference.PreferenceScreen;
import com.android.systemui.Dependency;
-import com.android.systemui.res.R;
import com.android.systemui.demomode.DemoModeController;
import com.android.systemui.fragments.FragmentService;
+import com.android.systemui.res.R;
import com.android.systemui.util.settings.GlobalSettings;
import javax.inject.Inject;
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java
index 550a65c..05ee35b 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java
@@ -38,14 +38,14 @@
import com.android.internal.util.ArrayUtils;
import com.android.systemui.DejankUtils;
-import com.android.systemui.res.R;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.demomode.DemoModeController;
import com.android.systemui.qs.QSHost;
+import com.android.systemui.res.R;
import com.android.systemui.settings.UserTracker;
-import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.statusbar.phone.SystemUIDialog;
+import com.android.systemui.statusbar.phone.ui.StatusBarIconController;
import com.android.systemui.util.leak.LeakDetector;
import dagger.Lazy;
@@ -56,7 +56,6 @@
import javax.inject.Inject;
-
/**
* @deprecated Don't use this class to listen to Secure Settings. Use {@code SecureSettings} instead
* or {@code SettingsObserver} to be able to specify the handler.
diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingActivity.java
index e4f1c87..42563fd 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingActivity.java
@@ -39,8 +39,8 @@
import com.android.internal.app.AlertActivity;
import com.android.internal.app.AlertController;
-import com.android.systemui.res.R;
import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.res.R;
import javax.inject.Inject;
diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingSecondaryUserActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingSecondaryUserActivity.java
index ea871be..64e35d9 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingSecondaryUserActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingSecondaryUserActivity.java
@@ -34,8 +34,8 @@
import com.android.internal.app.AlertActivity;
import com.android.internal.app.AlertController;
-import com.android.systemui.res.R;
import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.res.R;
import javax.inject.Inject;
diff --git a/packages/SystemUI/src/com/android/systemui/user/CreateUserActivity.java b/packages/SystemUI/src/com/android/systemui/user/CreateUserActivity.java
index 562feb2e..56b46624 100644
--- a/packages/SystemUI/src/com/android/systemui/user/CreateUserActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/user/CreateUserActivity.java
@@ -33,8 +33,8 @@
import com.android.internal.logging.UiEventLogger;
import com.android.settingslib.users.CreateUserDialogController;
-import com.android.systemui.res.R;
import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.res.R;
import javax.inject.Inject;
diff --git a/packages/SystemUI/src/com/android/systemui/util/annotations/WeaklyReferencedCallback.java b/packages/SystemUI/src/com/android/systemui/util/annotations/WeaklyReferencedCallback.java
index 855bba6..574e331 100644
--- a/packages/SystemUI/src/com/android/systemui/util/annotations/WeaklyReferencedCallback.java
+++ b/packages/SystemUI/src/com/android/systemui/util/annotations/WeaklyReferencedCallback.java
@@ -22,7 +22,6 @@
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
-
/**
* Descriptive annotation for clearly tagging callback types that are weakly
* referenced during registration.
diff --git a/packages/SystemUI/src/com/android/systemui/util/concurrency/GlobalConcurrencyModule.java b/packages/SystemUI/src/com/android/systemui/util/concurrency/GlobalConcurrencyModule.java
index e40d276..ecf1165 100644
--- a/packages/SystemUI/src/com/android/systemui/util/concurrency/GlobalConcurrencyModule.java
+++ b/packages/SystemUI/src/com/android/systemui/util/concurrency/GlobalConcurrencyModule.java
@@ -23,15 +23,15 @@
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dagger.qualifiers.UiBackground;
+import dagger.Binds;
+import dagger.Module;
+import dagger.Provides;
+
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import javax.inject.Singleton;
-import dagger.Binds;
-import dagger.Module;
-import dagger.Provides;
-
/**
* Dagger Module for classes found within the concurrent package.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/util/kotlin/Parallel.kt b/packages/SystemUI/src/com/android/systemui/util/kotlin/Parallel.kt
new file mode 100644
index 0000000..a47a2d6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/kotlin/Parallel.kt
@@ -0,0 +1,39 @@
+/*
+ * 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.util.kotlin
+
+import kotlinx.coroutines.CoroutineStart
+import kotlinx.coroutines.async
+import kotlinx.coroutines.awaitAll
+import kotlinx.coroutines.coroutineScope
+
+/** Like [Iterable.flatMap] but executes each [transform] invocation in a separate coroutine. */
+suspend fun <A, B> Iterable<A>.flatMapParallel(transform: suspend (A) -> Iterable<B>): List<B> =
+ mapParallel(transform).flatten()
+
+/** Like [Iterable.mapNotNull] but executes each [transform] invocation in a separate coroutine. */
+suspend fun <A, B> Iterable<A>.mapNotNullParallel(transform: suspend (A) -> B?): List<B> =
+ mapParallel(transform).filterNotNull()
+
+/** Like [Iterable.map] but executes each [transform] invocation in a separate coroutine. */
+suspend fun <A, B> Iterable<A>.mapParallel(transform: suspend (A) -> B): List<B> = coroutineScope {
+ map { async(start = CoroutineStart.LAZY) { transform(it) } }.awaitAll()
+}
+
+/** Like [mapValues] but executes each [transform] invocation in a separate coroutine. */
+suspend fun <K, A, B> Map<K, A>.mapValuesParallel(
+ transform: suspend (Map.Entry<K, A>) -> B
+): Map<K, B> = entries.mapParallel { it.key to transform(it) }.toMap()
diff --git a/packages/SystemUI/src/com/android/systemui/util/sensors/SensorModule.java b/packages/SystemUI/src/com/android/systemui/util/sensors/SensorModule.java
index 7934ab1..a7b6de2 100644
--- a/packages/SystemUI/src/com/android/systemui/util/sensors/SensorModule.java
+++ b/packages/SystemUI/src/com/android/systemui/util/sensors/SensorModule.java
@@ -24,19 +24,19 @@
import androidx.annotation.NonNull;
-import com.android.systemui.res.R;
import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.res.R;
import com.android.systemui.statusbar.policy.DevicePostureController;
import com.android.systemui.util.concurrency.DelayableExecutor;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.Map;
-
import dagger.Lazy;
import dagger.Module;
import dagger.Provides;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
/**
* Dagger module for Sensor related classes.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index cd82e1d..c69fb66 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -137,13 +137,13 @@
import com.android.systemui.volume.domain.interactor.VolumePanelNavigationInteractor;
import com.android.systemui.volume.ui.navigation.VolumeNavigator;
+import dagger.Lazy;
+
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
-import dagger.Lazy;
-
/**
* Visual presentation of the volume dialog.
*
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumePanelDialog.java b/packages/SystemUI/src/com/android/systemui/volume/VolumePanelDialog.java
index 6050387..3785f13 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumePanelDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumePanelDialog.java
@@ -51,8 +51,8 @@
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
import com.android.settingslib.media.MediaOutputConstants;
-import com.android.systemui.res.R;
import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.res.R;
import com.android.systemui.statusbar.phone.SystemUIDialog;
import java.util.ArrayList;
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeToolTipView.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeToolTipView.java
index 2143771..44382b6 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeToolTipView.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeToolTipView.java
@@ -28,8 +28,8 @@
import androidx.core.content.ContextCompat;
-import com.android.systemui.res.R;
import com.android.systemui.recents.TriangleShape;
+import com.android.systemui.res.R;
/**
* Tool tip view that draws an arrow that points to the volume dialog.
diff --git a/packages/SystemUI/src/com/android/systemui/wallet/dagger/WalletModule.java b/packages/SystemUI/src/com/android/systemui/wallet/dagger/WalletModule.java
index efba3e5..4841c78 100644
--- a/packages/SystemUI/src/com/android/systemui/wallet/dagger/WalletModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wallet/dagger/WalletModule.java
@@ -17,6 +17,7 @@
package com.android.systemui.wallet.dagger;
import android.app.Activity;
+import android.app.Service;
import android.content.Context;
import android.service.quickaccesswallet.QuickAccessWalletClient;
@@ -24,10 +25,9 @@
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.qs.tileimpl.QSTileImpl;
import com.android.systemui.qs.tiles.QuickAccessWalletTile;
+import com.android.systemui.wallet.controller.WalletContextualLocationsService;
import com.android.systemui.wallet.ui.WalletActivity;
-import java.util.concurrent.Executor;
-
import dagger.Binds;
import dagger.Module;
import dagger.Provides;
@@ -35,8 +35,7 @@
import dagger.multibindings.IntoMap;
import dagger.multibindings.StringKey;
-import android.app.Service;
-import com.android.systemui.wallet.controller.WalletContextualLocationsService;
+import java.util.concurrent.Executor;
/**
* Module for injecting classes in Wallet.
diff --git a/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletScreenController.java b/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletScreenController.java
index d21ccc9..53e6b4f 100644
--- a/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletScreenController.java
+++ b/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletScreenController.java
@@ -43,9 +43,9 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.UiEventLogger;
import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.systemui.res.R;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.FalsingManager;
+import com.android.systemui.res.R;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.policy.KeyguardStateController;
diff --git a/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/WallpaperRepository.kt b/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/WallpaperRepository.kt
index 1ba269e..041b6f9 100644
--- a/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/WallpaperRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/WallpaperRepository.kt
@@ -28,7 +28,9 @@
import com.android.systemui.user.data.model.SelectedUserModel
import com.android.systemui.user.data.model.SelectionStatus
import com.android.systemui.user.data.repository.UserRepository
+import com.android.systemui.utils.coroutines.flow.mapLatestConflated
import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
@@ -40,6 +42,7 @@
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.withContext
/** A repository storing information about the current wallpaper. */
interface WallpaperRepository {
@@ -55,6 +58,7 @@
@Inject
constructor(
@Background scope: CoroutineScope,
+ @Background private val bgDispatcher: CoroutineDispatcher,
broadcastDispatcher: BroadcastDispatcher,
userRepository: UserRepository,
private val wallpaperManager: WallpaperManager,
@@ -87,14 +91,15 @@
if (!wallpaperManager.isWallpaperSupported || !deviceSupportsAodWallpaper) {
MutableStateFlow(null).asStateFlow()
} else {
- combine(wallpaperChanged, selectedUser) { _, selectedUser ->
- getWallpaper(selectedUser)
- }
+ combine(wallpaperChanged, selectedUser, ::Pair)
+ .mapLatestConflated { (_, selectedUser) -> getWallpaper(selectedUser) }
.stateIn(
scope,
// Always be listening for wallpaper changes.
SharingStarted.Eagerly,
- initialValue = getWallpaper(userRepository.selectedUser.value),
+ // The initial value is null, but it should get updated pretty quickly because
+ // the `combine` should immediately kick off a fetch.
+ initialValue = null,
)
}
@@ -111,7 +116,9 @@
initialValue = wallpaperInfo.value?.supportsAmbientMode() == true,
)
- private fun getWallpaper(selectedUser: SelectedUserModel): WallpaperInfo? {
- return wallpaperManager.getWallpaperInfoForUser(selectedUser.userInfo.id)
+ private suspend fun getWallpaper(selectedUser: SelectedUserModel): WallpaperInfo? {
+ return withContext(bgDispatcher) {
+ wallpaperManager.getWallpaperInfoForUser(selectedUser.userInfo.id)
+ }
}
}
diff --git a/packages/SystemUI/tests/robolectric/src/com/android/systemui/robotests/SysuiResourceLoadingTest.java b/packages/SystemUI/tests/robolectric/src/com/android/systemui/robotests/SysuiResourceLoadingTest.java
index 205168e..a48d179 100644
--- a/packages/SystemUI/tests/robolectric/src/com/android/systemui/robotests/SysuiResourceLoadingTest.java
+++ b/packages/SystemUI/tests/robolectric/src/com/android/systemui/robotests/SysuiResourceLoadingTest.java
@@ -16,9 +16,11 @@
package com.android.systemui.robotests;
+import static com.google.common.truth.Truth.assertThat;
+
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
-import static com.google.common.truth.Truth.assertThat;
+
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextManagerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextManagerTest.java
index 11d31c6..8c4179d 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextManagerTest.java
@@ -69,6 +69,8 @@
import com.android.systemui.util.kotlin.JavaAdapter;
import com.android.systemui.util.time.FakeSystemClock;
+import kotlinx.coroutines.test.TestScope;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -81,8 +83,6 @@
import java.util.HashMap;
import java.util.List;
-import kotlinx.coroutines.test.TestScope;
-
@SmallTest
@RunWith(AndroidTestingRunner.class)
public class CarrierTextManagerTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockAccessibilityDelegateTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockAccessibilityDelegateTest.java
index 8401e67..edf29c5 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockAccessibilityDelegateTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockAccessibilityDelegateTest.java
@@ -27,8 +27,8 @@
import androidx.test.filters.SmallTest;
-import com.android.systemui.res.R;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.res.R;
import org.junit.Before;
import org.junit.Test;
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerBaseTest.java
index f1dfdf4..07504c7 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerBaseTest.java
@@ -20,8 +20,6 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import static kotlinx.coroutines.flow.FlowKt.emptyFlow;
-
import android.view.View;
import android.view.ViewTreeObserver;
import android.widget.FrameLayout;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationGestureDetectorTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationGestureDetectorTest.java
index 36ae3c0..ad02179 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationGestureDetectorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationGestureDetectorTest.java
@@ -44,7 +44,6 @@
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
-
@SmallTest
@RunWith(AndroidTestingRunner.class)
public class MagnificationGestureDetectorTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityTargetAdapterTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityTargetAdapterTest.java
index 403385f..630db62 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityTargetAdapterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityTargetAdapterTest.java
@@ -28,9 +28,9 @@
import androidx.test.filters.SmallTest;
import com.android.internal.accessibility.dialog.AccessibilityTarget;
-import com.android.systemui.res.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.accessibility.floatingmenu.AccessibilityTargetAdapter.ViewHolder;
+import com.android.systemui.res.R;
import org.junit.Before;
import org.junit.Test;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AnnotationLinkSpanTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AnnotationLinkSpanTest.java
index 43ebeee..4b87588 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AnnotationLinkSpanTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AnnotationLinkSpanTest.java
@@ -26,8 +26,8 @@
import androidx.test.filters.SmallTest;
-import com.android.systemui.res.R;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.res.R;
import org.junit.Before;
import org.junit.Test;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/TransitionAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/TransitionAnimatorTest.kt
index c380a51..fbe1184 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/animation/TransitionAnimatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/TransitionAnimatorTest.kt
@@ -64,14 +64,7 @@
@get:Rule(order = 0) val deviceEmulationRule = DeviceEmulationRule(emulationSpec)
@get:Rule(order = 1) val activityRule = ActivityScenarioRule(EmptyTestActivity::class.java)
- @get:Rule(order = 2)
- val motionRule =
- ViewMotionTestRule<EmptyTestActivity>(
- pathManager,
- { activityRule.scenario },
- context = context,
- bitmapDiffer = null,
- )
+ @get:Rule(order = 2) val motionRule = ViewMotionTestRule(pathManager, { activityRule.scenario })
@Test
fun backgroundAnimation_whenLaunching() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/assist/ui/DisplayUtilsTest.java b/packages/SystemUI/tests/src/com/android/systemui/assist/ui/DisplayUtilsTest.java
index 957443a..4d582ab 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/assist/ui/DisplayUtilsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/assist/ui/DisplayUtilsTest.java
@@ -25,8 +25,8 @@
import androidx.test.filters.SmallTest;
-import com.android.systemui.res.R;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.res.R;
import org.junit.Before;
import org.junit.Test;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/battery/BatteryMeterViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/battery/BatteryMeterViewControllerTest.java
index 323f15a..14eff2f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/battery/BatteryMeterViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/battery/BatteryMeterViewControllerTest.java
@@ -33,9 +33,9 @@
import androidx.test.filters.SmallTest;
-import com.android.systemui.res.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.flags.FakeFeatureFlags;
+import com.android.systemui.res.R;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.phone.StatusBarLocation;
import com.android.systemui.statusbar.policy.BatteryController;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinderTest.kt
index 01d9df8..ec2b104 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinderTest.kt
@@ -17,12 +17,10 @@
package com.android.systemui.biometrics.ui.binder
import android.animation.Animator
-import android.app.ActivityTaskManager
import android.graphics.Rect
import android.hardware.biometrics.SensorLocationInternal
import android.hardware.display.DisplayManager
import android.hardware.display.DisplayManagerGlobal
-import android.os.Handler
import android.testing.TestableLooper
import android.view.Display
import android.view.DisplayInfo
@@ -32,67 +30,31 @@
import android.view.WindowInsets
import android.view.WindowManager
import android.view.WindowMetrics
+import android.view.layoutInflater
+import android.view.windowManager
import androidx.test.filters.SmallTest
import com.airbnb.lottie.LottieAnimationView
-import com.android.keyguard.KeyguardSecurityModel
-import com.android.keyguard.KeyguardUpdateMonitor
+import com.android.keyguard.keyguardUpdateMonitor
import com.android.systemui.SysuiTestCase
import com.android.systemui.biometrics.FingerprintInteractiveToAuthProvider
-import com.android.systemui.biometrics.FpsUnlockTracker
-import com.android.systemui.biometrics.data.repository.FakeBiometricStatusRepository
-import com.android.systemui.biometrics.data.repository.FakeDisplayStateRepository
-import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository
-import com.android.systemui.biometrics.domain.interactor.BiometricStatusInteractor
-import com.android.systemui.biometrics.domain.interactor.BiometricStatusInteractorImpl
-import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractorImpl
-import com.android.systemui.biometrics.domain.interactor.SideFpsSensorInteractor
+import com.android.systemui.biometrics.data.repository.biometricStatusRepository
+import com.android.systemui.biometrics.data.repository.fingerprintPropertyRepository
import com.android.systemui.biometrics.shared.model.AuthenticationReason
import com.android.systemui.biometrics.shared.model.DisplayRotation
import com.android.systemui.biometrics.shared.model.FingerprintSensorType
import com.android.systemui.biometrics.shared.model.SensorStrength
-import com.android.systemui.biometrics.ui.viewmodel.SideFpsOverlayViewModel
-import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository
-import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor
-import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerCallbackInteractor
-import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
-import com.android.systemui.bouncer.ui.BouncerView
-import com.android.systemui.classifier.FalsingCollector
-import com.android.systemui.deviceentry.domain.interactor.DeviceEntryFaceAuthInteractor
-import com.android.systemui.deviceentry.domain.interactor.DeviceEntryFingerprintAuthInteractor
-import com.android.systemui.deviceentry.domain.interactor.deviceEntryFingerprintAuthInteractor
-import com.android.systemui.display.data.repository.FakeDisplayRepository
-import com.android.systemui.keyguard.DismissCallbackRegistry
-import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository
-import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFingerprintAuthRepository
-import com.android.systemui.keyguard.data.repository.FakeTrustRepository
-import com.android.systemui.keyguard.data.repository.biometricSettingsRepository
-import com.android.systemui.keyguard.domain.interactor.DeviceEntrySideFpsOverlayInteractor
-import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
-import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
-import com.android.systemui.keyguard.domain.interactor.keyguardInteractor
-import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor
-import com.android.systemui.keyguard.ui.viewmodel.SideFpsProgressBarViewModel
-import com.android.systemui.log.SideFpsLogger
-import com.android.systemui.log.logcatLogBuffer
-import com.android.systemui.plugins.statusbar.StatusBarStateController
-import com.android.systemui.power.domain.interactor.powerInteractor
+import com.android.systemui.bouncer.data.repository.keyguardBouncerRepository
+import com.android.systemui.display.data.repository.displayRepository
+import com.android.systemui.display.data.repository.displayStateRepository
+import com.android.systemui.keyguard.ui.viewmodel.sideFpsProgressBarViewModel
+import com.android.systemui.kosmos.testScope
import com.android.systemui.res.R
-import com.android.systemui.scene.domain.interactor.sceneInteractor
-import com.android.systemui.statusbar.phone.dozeServiceHost
-import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.testKosmos
-import com.android.systemui.unfold.compat.ScreenSizeFoldProvider
-import com.android.systemui.user.domain.interactor.SelectedUserInteractor
-import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.mockito.whenever
-import com.android.systemui.util.time.FakeSystemClock
-import java.util.Optional
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.TestScope
-import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
@@ -120,42 +82,14 @@
private val kosmos = testKosmos()
@JvmField @Rule var mockitoRule: MockitoRule = MockitoJUnit.rule()
- @Mock private lateinit var activityTaskManager: ActivityTaskManager
@Mock private lateinit var displayManager: DisplayManager
- @Mock private lateinit var faceAuthInteractor: DeviceEntryFaceAuthInteractor
@Mock
private lateinit var fingerprintInteractiveToAuthProvider: FingerprintInteractiveToAuthProvider
- @Mock private lateinit var fpsUnlockTracker: FpsUnlockTracker
- @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
@Mock private lateinit var layoutInflater: LayoutInflater
- @Mock private lateinit var screenSizeFoldProvider: ScreenSizeFoldProvider
- @Mock private lateinit var selectedUserInteractor: SelectedUserInteractor
@Mock private lateinit var sideFpsView: View
- @Mock private lateinit var windowManager: WindowManager
private val contextDisplayInfo = DisplayInfo()
- private val bouncerRepository = FakeKeyguardBouncerRepository()
- private val biometricSettingsRepository = FakeBiometricSettingsRepository()
- private val biometricStatusRepository = FakeBiometricStatusRepository()
- private val deviceEntryFingerprintAuthRepository = FakeDeviceEntryFingerprintAuthRepository()
- private val displayRepository = FakeDisplayRepository()
- private val displayStateRepository = FakeDisplayStateRepository()
- private val fingerprintPropertyRepository = FakeFingerprintPropertyRepository()
-
- private lateinit var underTest: SideFpsOverlayViewBinder
-
- private lateinit var alternateBouncerInteractor: AlternateBouncerInteractor
- private lateinit var biometricStatusInteractor: BiometricStatusInteractor
- private lateinit var deviceEntrySideFpsOverlayInteractor: DeviceEntrySideFpsOverlayInteractor
- private lateinit var displayStateInteractor: DisplayStateInteractorImpl
- private lateinit var primaryBouncerInteractor: PrimaryBouncerInteractor
- private lateinit var sfpsSensorInteractor: SideFpsSensorInteractor
-
- private lateinit var sideFpsProgressBarViewModel: SideFpsProgressBarViewModel
-
- private lateinit var viewModel: SideFpsOverlayViewModel
-
private var displayWidth: Int = 0
private var displayHeight: Int = 0
private var boundsWidth: Int = 0
@@ -164,9 +98,6 @@
private lateinit var deviceConfig: DeviceConfig
private lateinit var sensorLocation: SensorLocationInternal
- private val testScope = TestScope(StandardTestDispatcher())
- private val fakeExecutor = FakeExecutor(FakeSystemClock())
-
enum class DeviceConfig {
X_ALIGNED,
Y_ALIGNED,
@@ -184,122 +115,13 @@
Display(mock(DisplayManagerGlobal::class.java), 1, contextDisplayInfo, resources)
)
- alternateBouncerInteractor =
- AlternateBouncerInteractor(
- mock(StatusBarStateController::class.java),
- mock(KeyguardStateController::class.java),
- bouncerRepository,
- fingerprintPropertyRepository,
- biometricSettingsRepository,
- FakeSystemClock(),
- keyguardUpdateMonitor,
- { mock(DeviceEntryFingerprintAuthInteractor::class.java) },
- { mock(KeyguardInteractor::class.java) },
- { mock(KeyguardTransitionInteractor::class.java) },
- testScope.backgroundScope,
- )
-
- biometricStatusInteractor =
- BiometricStatusInteractorImpl(
- activityTaskManager,
- biometricStatusRepository,
- fingerprintPropertyRepository
- )
-
- displayStateInteractor =
- DisplayStateInteractorImpl(
- testScope.backgroundScope,
- mContext,
- fakeExecutor,
- displayStateRepository,
- displayRepository,
- )
- displayStateInteractor.setScreenSizeFoldProvider(screenSizeFoldProvider)
-
- primaryBouncerInteractor =
- 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),
- mContext,
- keyguardUpdateMonitor,
- FakeTrustRepository(),
- testScope.backgroundScope,
- selectedUserInteractor,
- faceAuthInteractor
- )
-
- deviceEntrySideFpsOverlayInteractor =
- DeviceEntrySideFpsOverlayInteractor(
- testScope.backgroundScope,
- mContext,
- deviceEntryFingerprintAuthRepository,
- kosmos.sceneInteractor,
- primaryBouncerInteractor,
- alternateBouncerInteractor,
- keyguardUpdateMonitor
- )
+ kosmos.layoutInflater = layoutInflater
whenever(fingerprintInteractiveToAuthProvider.enabledForCurrentUser)
.thenReturn(MutableStateFlow(false))
- sfpsSensorInteractor =
- SideFpsSensorInteractor(
- mContext,
- fingerprintPropertyRepository,
- windowManager,
- displayStateInteractor,
- Optional.of(fingerprintInteractiveToAuthProvider),
- kosmos.biometricSettingsRepository,
- kosmos.keyguardTransitionInteractor,
- SideFpsLogger(logcatLogBuffer("SfpsLogger"))
- )
-
- sideFpsProgressBarViewModel =
- SideFpsProgressBarViewModel(
- mContext,
- biometricStatusInteractor,
- kosmos.deviceEntryFingerprintAuthInteractor,
- sfpsSensorInteractor,
- kosmos.dozeServiceHost,
- kosmos.keyguardInteractor,
- displayStateInteractor,
- UnconfinedTestDispatcher(),
- testScope.backgroundScope,
- kosmos.powerInteractor,
- )
-
- viewModel =
- SideFpsOverlayViewModel(
- mContext,
- biometricStatusInteractor,
- deviceEntrySideFpsOverlayInteractor,
- displayStateInteractor,
- sfpsSensorInteractor,
- sideFpsProgressBarViewModel
- )
-
- underTest =
- SideFpsOverlayViewBinder(
- testScope.backgroundScope,
- mContext,
- { biometricStatusInteractor },
- { displayStateInteractor },
- { deviceEntrySideFpsOverlayInteractor },
- { fpsUnlockTracker },
- { layoutInflater },
- { sideFpsProgressBarViewModel },
- { sfpsSensorInteractor },
- { windowManager }
- )
-
context.addMockSystemService(DisplayManager::class.java, displayManager)
- context.addMockSystemService(WindowManager::class.java, windowManager)
+ context.addMockSystemService(WindowManager::class.java, kosmos.windowManager)
`when`(layoutInflater.inflate(R.layout.sidefps_view, null, false)).thenReturn(sideFpsView)
`when`(sideFpsView.requireViewById<LottieAnimationView>(eq(R.id.sidefps_animation)))
@@ -320,16 +142,16 @@
@Test
fun verifyIndicatorNotAdded_whenInRearDisplayMode() {
- testScope.runTest {
+ kosmos.testScope.runTest {
setupTestConfiguration(
DeviceConfig.X_ALIGNED,
rotation = DisplayRotation.ROTATION_0,
isInRearDisplayMode = true
)
- biometricStatusRepository.setFingerprintAuthenticationReason(
+ kosmos.biometricStatusRepository.setFingerprintAuthenticationReason(
AuthenticationReason.NotRunning
)
- sideFpsProgressBarViewModel.setVisible(false)
+ kosmos.sideFpsProgressBarViewModel.setVisible(false)
updatePrimaryBouncer(
isShowing = true,
isAnimatingAway = false,
@@ -338,22 +160,22 @@
)
runCurrent()
- verify(windowManager, never()).addView(any(), any())
+ verify(kosmos.windowManager, never()).addView(any(), any())
}
}
@Test
fun verifyIndicatorShowAndHide_onPrimaryBouncerShowAndHide() {
- testScope.runTest {
+ kosmos.testScope.runTest {
setupTestConfiguration(
DeviceConfig.X_ALIGNED,
rotation = DisplayRotation.ROTATION_0,
isInRearDisplayMode = false
)
- biometricStatusRepository.setFingerprintAuthenticationReason(
+ kosmos.biometricStatusRepository.setFingerprintAuthenticationReason(
AuthenticationReason.NotRunning
)
- sideFpsProgressBarViewModel.setVisible(false)
+ kosmos.sideFpsProgressBarViewModel.setVisible(false)
// Show primary bouncer
updatePrimaryBouncer(
isShowing = true,
@@ -363,7 +185,7 @@
)
runCurrent()
- verify(windowManager).addView(any(), any())
+ verify(kosmos.windowManager).addView(any(), any())
// Hide primary bouncer
updatePrimaryBouncer(
@@ -374,45 +196,45 @@
)
runCurrent()
- verify(windowManager).removeView(any())
+ verify(kosmos.windowManager).removeView(any())
}
}
@Test
fun verifyIndicatorShowAndHide_onAlternateBouncerShowAndHide() {
- testScope.runTest {
+ kosmos.testScope.runTest {
setupTestConfiguration(
DeviceConfig.X_ALIGNED,
rotation = DisplayRotation.ROTATION_0,
isInRearDisplayMode = false
)
- biometricStatusRepository.setFingerprintAuthenticationReason(
+ kosmos.biometricStatusRepository.setFingerprintAuthenticationReason(
AuthenticationReason.NotRunning
)
- sideFpsProgressBarViewModel.setVisible(false)
+ kosmos.sideFpsProgressBarViewModel.setVisible(false)
// Show alternate bouncer
- bouncerRepository.setAlternateVisible(true)
+ kosmos.keyguardBouncerRepository.setAlternateVisible(true)
runCurrent()
- verify(windowManager).addView(any(), any())
+ verify(kosmos.windowManager).addView(any(), any())
// Hide alternate bouncer
- bouncerRepository.setAlternateVisible(false)
+ kosmos.keyguardBouncerRepository.setAlternateVisible(false)
runCurrent()
- verify(windowManager).removeView(any())
+ verify(kosmos.windowManager).removeView(any())
}
}
@Test
fun verifyIndicatorShownAndHidden_onSystemServerAuthenticationStartedAndStopped() {
- testScope.runTest {
+ kosmos.testScope.runTest {
setupTestConfiguration(
DeviceConfig.X_ALIGNED,
rotation = DisplayRotation.ROTATION_0,
isInRearDisplayMode = false
)
- sideFpsProgressBarViewModel.setVisible(false)
+ kosmos.sideFpsProgressBarViewModel.setVisible(false)
updatePrimaryBouncer(
isShowing = false,
isAnimatingAway = false,
@@ -420,20 +242,20 @@
isUnlockingWithFpAllowed = true
)
// System server authentication started
- biometricStatusRepository.setFingerprintAuthenticationReason(
+ kosmos.biometricStatusRepository.setFingerprintAuthenticationReason(
AuthenticationReason.BiometricPromptAuthentication
)
runCurrent()
- verify(windowManager).addView(any(), any())
+ verify(kosmos.windowManager).addView(any(), any())
// System server authentication stopped
- biometricStatusRepository.setFingerprintAuthenticationReason(
+ kosmos.biometricStatusRepository.setFingerprintAuthenticationReason(
AuthenticationReason.NotRunning
)
runCurrent()
- verify(windowManager).removeView(any())
+ verify(kosmos.windowManager).removeView(any())
}
}
@@ -441,17 +263,17 @@
// On progress bar hidden - show indicator
@Test
fun verifyIndicatorProgressBarInteraction() {
- testScope.runTest {
+ kosmos.testScope.runTest {
// Pre-auth conditions
setupTestConfiguration(
DeviceConfig.X_ALIGNED,
rotation = DisplayRotation.ROTATION_0,
isInRearDisplayMode = false
)
- biometricStatusRepository.setFingerprintAuthenticationReason(
+ kosmos.biometricStatusRepository.setFingerprintAuthenticationReason(
AuthenticationReason.NotRunning
)
- sideFpsProgressBarViewModel.setVisible(false)
+ kosmos.sideFpsProgressBarViewModel.setVisible(false)
// Show primary bouncer
updatePrimaryBouncer(
@@ -462,26 +284,26 @@
)
runCurrent()
- val inOrder = inOrder(windowManager)
+ val inOrder = inOrder(kosmos.windowManager)
// Verify indicator shown
- inOrder.verify(windowManager).addView(any(), any())
+ inOrder.verify(kosmos.windowManager).addView(any(), any())
// Set progress bar visible
- sideFpsProgressBarViewModel.setVisible(true)
+ kosmos.sideFpsProgressBarViewModel.setVisible(true)
runCurrent()
// Verify indicator hidden
- inOrder.verify(windowManager).removeView(any())
+ inOrder.verify(kosmos.windowManager).removeView(any())
// Set progress bar invisible
- sideFpsProgressBarViewModel.setVisible(false)
+ kosmos.sideFpsProgressBarViewModel.setVisible(false)
runCurrent()
// Verify indicator shown
- inOrder.verify(windowManager).addView(any(), any())
+ inOrder.verify(kosmos.windowManager).addView(any(), any())
}
}
@@ -491,14 +313,16 @@
fpsDetectionRunning: Boolean,
isUnlockingWithFpAllowed: Boolean,
) {
- bouncerRepository.setPrimaryShow(isShowing)
- bouncerRepository.setPrimaryStartingToHide(false)
+ kosmos.keyguardBouncerRepository.setPrimaryShow(isShowing)
+ kosmos.keyguardBouncerRepository.setPrimaryStartingToHide(false)
val primaryStartDisappearAnimation = if (isAnimatingAway) Runnable {} else null
- bouncerRepository.setPrimaryStartDisappearAnimation(primaryStartDisappearAnimation)
+ kosmos.keyguardBouncerRepository.setPrimaryStartDisappearAnimation(
+ primaryStartDisappearAnimation
+ )
- whenever(keyguardUpdateMonitor.isFingerprintDetectionRunning)
+ whenever(kosmos.keyguardUpdateMonitor.isFingerprintDetectionRunning)
.thenReturn(fpsDetectionRunning)
- whenever(keyguardUpdateMonitor.isUnlockingWithFingerprintAllowed)
+ whenever(kosmos.keyguardUpdateMonitor.isUnlockingWithFingerprintAllowed)
.thenReturn(isUnlockingWithFpAllowed)
mContext.orCreateTestableResources.addOverride(
R.bool.config_show_sidefps_hint_on_bouncer,
@@ -530,7 +354,7 @@
}
}
- whenever(windowManager.maximumWindowMetrics)
+ whenever(kosmos.windowManager.maximumWindowMetrics)
.thenReturn(
WindowMetrics(
Rect(0, 0, displayWidth, displayHeight),
@@ -540,17 +364,17 @@
contextDisplayInfo.uniqueId = DISPLAY_ID
- fingerprintPropertyRepository.setProperties(
+ kosmos.fingerprintPropertyRepository.setProperties(
sensorId = 1,
strength = SensorStrength.STRONG,
sensorType = FingerprintSensorType.POWER_BUTTON,
sensorLocations = mapOf(DISPLAY_ID to sensorLocation)
)
- displayStateRepository.setIsInRearDisplayMode(isInRearDisplayMode)
- displayStateRepository.setCurrentRotation(rotation)
- displayRepository.emitDisplayChangeEvent(0)
- underTest.start()
+ kosmos.displayStateRepository.setIsInRearDisplayMode(isInRearDisplayMode)
+ kosmos.displayStateRepository.setCurrentRotation(rotation)
+ kosmos.displayRepository.emitDisplayChangeEvent(0)
+ kosmos.sideFpsOverlayViewBinder.start()
runCurrent()
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModelTest.kt
index 05ec64e..b065393 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModelTest.kt
@@ -22,74 +22,39 @@
import android.graphics.Rect
import android.hardware.biometrics.SensorLocationInternal
import android.hardware.display.DisplayManagerGlobal
-import android.os.Handler
import android.view.Display
import android.view.DisplayInfo
import android.view.WindowInsets
-import android.view.WindowManager
import android.view.WindowMetrics
+import android.view.windowManager
import androidx.test.filters.SmallTest
import com.airbnb.lottie.model.KeyPath
-import com.android.keyguard.KeyguardSecurityModel
-import com.android.keyguard.KeyguardUpdateMonitor
+import com.android.keyguard.keyguardUpdateMonitor
import com.android.settingslib.Utils
import com.android.systemui.Flags.FLAG_CONSTRAINT_BP
import com.android.systemui.SysuiTestCase
import com.android.systemui.biometrics.FingerprintInteractiveToAuthProvider
-import com.android.systemui.biometrics.data.repository.FakeBiometricStatusRepository
-import com.android.systemui.biometrics.data.repository.FakeDisplayStateRepository
-import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository
import com.android.systemui.biometrics.data.repository.biometricStatusRepository
-import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractorImpl
-import com.android.systemui.biometrics.domain.interactor.SideFpsSensorInteractor
-import com.android.systemui.biometrics.domain.interactor.biometricStatusInteractor
+import com.android.systemui.biometrics.data.repository.fingerprintPropertyRepository
+import com.android.systemui.biometrics.domain.interactor.displayStateInteractor
import com.android.systemui.biometrics.shared.model.AuthenticationReason
import com.android.systemui.biometrics.shared.model.DisplayRotation
import com.android.systemui.biometrics.shared.model.FingerprintSensorType
import com.android.systemui.biometrics.shared.model.LottieCallback
import com.android.systemui.biometrics.shared.model.SensorStrength
-import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository
-import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor
-import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerCallbackInteractor
-import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
-import com.android.systemui.bouncer.ui.BouncerView
-import com.android.systemui.classifier.FalsingCollector
+import com.android.systemui.bouncer.data.repository.keyguardBouncerRepository
import com.android.systemui.coroutines.collectLastValue
-import com.android.systemui.deviceentry.domain.interactor.DeviceEntryFaceAuthInteractor
-import com.android.systemui.deviceentry.domain.interactor.DeviceEntryFingerprintAuthInteractor
-import com.android.systemui.deviceentry.domain.interactor.deviceEntryFingerprintAuthInteractor
-import com.android.systemui.display.data.repository.FakeDisplayRepository
-import com.android.systemui.keyguard.DismissCallbackRegistry
-import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository
-import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFingerprintAuthRepository
-import com.android.systemui.keyguard.data.repository.FakeTrustRepository
-import com.android.systemui.keyguard.data.repository.biometricSettingsRepository
-import com.android.systemui.keyguard.domain.interactor.DeviceEntrySideFpsOverlayInteractor
-import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
-import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
-import com.android.systemui.keyguard.domain.interactor.keyguardInteractor
-import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor
-import com.android.systemui.keyguard.ui.viewmodel.SideFpsProgressBarViewModel
-import com.android.systemui.kosmos.testDispatcher
-import com.android.systemui.log.SideFpsLogger
-import com.android.systemui.log.logcatLogBuffer
-import com.android.systemui.plugins.statusbar.StatusBarStateController
-import com.android.systemui.power.domain.interactor.powerInteractor
+import com.android.systemui.display.data.repository.displayRepository
+import com.android.systemui.display.data.repository.displayStateRepository
+import com.android.systemui.keyguard.ui.viewmodel.sideFpsProgressBarViewModel
+import com.android.systemui.kosmos.testScope
import com.android.systemui.res.R
-import com.android.systemui.scene.domain.interactor.sceneInteractor
-import com.android.systemui.statusbar.phone.dozeServiceHost
-import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.testKosmos
import com.android.systemui.unfold.compat.ScreenSizeFoldProvider
-import com.android.systemui.user.domain.interactor.SelectedUserInteractor
-import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.mockito.whenever
-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.MutableStateFlow
-import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
@@ -111,24 +76,12 @@
private val kosmos = testKosmos()
@JvmField @Rule var mockitoRule: MockitoRule = MockitoJUnit.rule()
- @Mock private lateinit var faceAuthInteractor: DeviceEntryFaceAuthInteractor
@Mock
private lateinit var fingerprintInteractiveToAuthProvider: FingerprintInteractiveToAuthProvider
- @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
@Mock private lateinit var screenSizeFoldProvider: ScreenSizeFoldProvider
- @Mock private lateinit var selectedUserInteractor: SelectedUserInteractor
- @Mock private lateinit var windowManager: WindowManager
private val contextDisplayInfo = DisplayInfo()
- private val bouncerRepository = FakeKeyguardBouncerRepository()
- private val biometricSettingsRepository = FakeBiometricSettingsRepository()
- private val biometricStatusRepository = FakeBiometricStatusRepository()
- private val deviceEntryFingerprintAuthRepository = FakeDeviceEntryFingerprintAuthRepository()
- private val displayRepository = FakeDisplayRepository()
- private val displayStateRepository = FakeDisplayStateRepository()
- private val fingerprintPropertyRepository = FakeFingerprintPropertyRepository()
-
private val indicatorColor =
Utils.getColorAttrDefaultColor(
context,
@@ -147,16 +100,6 @@
private val color_blue400 =
context.getColor(com.android.settingslib.color.R.color.settingslib_color_blue400)
- private lateinit var alternateBouncerInteractor: AlternateBouncerInteractor
- private lateinit var deviceEntrySideFpsOverlayInteractor: DeviceEntrySideFpsOverlayInteractor
- private lateinit var displayStateInteractor: DisplayStateInteractorImpl
- private lateinit var primaryBouncerInteractor: PrimaryBouncerInteractor
- private lateinit var sfpsSensorInteractor: SideFpsSensorInteractor
-
- private lateinit var sideFpsProgressBarViewModel: SideFpsProgressBarViewModel
-
- private lateinit var underTest: SideFpsOverlayViewModel
-
private var displayWidth: Int = 0
private var displayHeight: Int = 0
private var boundsWidth: Int = 0
@@ -165,9 +108,6 @@
private lateinit var deviceConfig: DeviceConfig
private lateinit var sensorLocation: SensorLocationInternal
- private val testScope = TestScope(StandardTestDispatcher())
- private val fakeExecutor = FakeExecutor(FakeSystemClock())
-
enum class DeviceConfig {
X_ALIGNED,
Y_ALIGNED,
@@ -182,129 +122,40 @@
.thenReturn(
Display(mock(DisplayManagerGlobal::class.java), 1, contextDisplayInfo, resources)
)
- kosmos.biometricStatusRepository = biometricStatusRepository
-
- alternateBouncerInteractor =
- AlternateBouncerInteractor(
- mock(StatusBarStateController::class.java),
- mock(KeyguardStateController::class.java),
- bouncerRepository,
- fingerprintPropertyRepository,
- biometricSettingsRepository,
- FakeSystemClock(),
- keyguardUpdateMonitor,
- { mock(DeviceEntryFingerprintAuthInteractor::class.java) },
- { mock(KeyguardInteractor::class.java) },
- { mock(KeyguardTransitionInteractor::class.java) },
- testScope.backgroundScope,
- )
-
- displayStateInteractor =
- DisplayStateInteractorImpl(
- testScope.backgroundScope,
- mContext,
- fakeExecutor,
- displayStateRepository,
- displayRepository,
- )
- displayStateInteractor.setScreenSizeFoldProvider(screenSizeFoldProvider)
-
- primaryBouncerInteractor =
- 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),
- mContext,
- keyguardUpdateMonitor,
- FakeTrustRepository(),
- testScope.backgroundScope,
- selectedUserInteractor,
- faceAuthInteractor
- )
-
- deviceEntrySideFpsOverlayInteractor =
- DeviceEntrySideFpsOverlayInteractor(
- testScope.backgroundScope,
- mContext,
- deviceEntryFingerprintAuthRepository,
- kosmos.sceneInteractor,
- primaryBouncerInteractor,
- alternateBouncerInteractor,
- keyguardUpdateMonitor
- )
+ kosmos.displayStateInteractor.setScreenSizeFoldProvider(screenSizeFoldProvider)
whenever(fingerprintInteractiveToAuthProvider.enabledForCurrentUser)
.thenReturn(MutableStateFlow(false))
-
- sfpsSensorInteractor =
- SideFpsSensorInteractor(
- mContext,
- fingerprintPropertyRepository,
- windowManager,
- displayStateInteractor,
- Optional.of(fingerprintInteractiveToAuthProvider),
- kosmos.biometricSettingsRepository,
- kosmos.keyguardTransitionInteractor,
- SideFpsLogger(logcatLogBuffer("SfpsLogger"))
- )
-
- sideFpsProgressBarViewModel =
- SideFpsProgressBarViewModel(
- mContext,
- kosmos.biometricStatusInteractor,
- kosmos.deviceEntryFingerprintAuthInteractor,
- sfpsSensorInteractor,
- kosmos.dozeServiceHost,
- kosmos.keyguardInteractor,
- displayStateInteractor,
- kosmos.testDispatcher,
- testScope.backgroundScope,
- kosmos.powerInteractor
- )
-
- underTest =
- SideFpsOverlayViewModel(
- mContext,
- kosmos.biometricStatusInteractor,
- deviceEntrySideFpsOverlayInteractor,
- displayStateInteractor,
- sfpsSensorInteractor,
- sideFpsProgressBarViewModel,
- )
}
@Test
fun updatesOverlayViewProperties_onDisplayRotationChange_xAlignedSensor() {
- testScope.runTest {
+ kosmos.testScope.runTest {
setupTestConfiguration(
DeviceConfig.X_ALIGNED,
rotation = DisplayRotation.ROTATION_0,
isInRearDisplayMode = false
)
- val overlayViewProperties by collectLastValue(underTest.overlayViewProperties)
+ val overlayViewProperties by
+ collectLastValue(kosmos.sideFpsOverlayViewModel.overlayViewProperties)
runCurrent()
assertThat(overlayViewProperties?.indicatorAsset).isEqualTo(R.raw.sfps_pulse_landscape)
assertThat(overlayViewProperties?.overlayViewRotation).isEqualTo(0f)
- displayStateRepository.setCurrentRotation(DisplayRotation.ROTATION_90)
+ kosmos.displayStateRepository.setCurrentRotation(DisplayRotation.ROTATION_90)
assertThat(overlayViewProperties?.indicatorAsset).isEqualTo(R.raw.sfps_pulse)
assertThat(overlayViewProperties?.overlayViewRotation).isEqualTo(180f)
- displayStateRepository.setCurrentRotation(DisplayRotation.ROTATION_180)
+ kosmos.displayStateRepository.setCurrentRotation(DisplayRotation.ROTATION_180)
assertThat(overlayViewProperties?.indicatorAsset).isEqualTo(R.raw.sfps_pulse_landscape)
assertThat(overlayViewProperties?.overlayViewRotation).isEqualTo(180f)
- displayStateRepository.setCurrentRotation(DisplayRotation.ROTATION_270)
+ kosmos.displayStateRepository.setCurrentRotation(DisplayRotation.ROTATION_270)
assertThat(overlayViewProperties?.indicatorAsset).isEqualTo(R.raw.sfps_pulse)
assertThat(overlayViewProperties?.overlayViewRotation).isEqualTo(0f)
@@ -313,31 +164,32 @@
@Test
fun updatesOverlayViewProperties_onDisplayRotationChange_yAlignedSensor() {
- testScope.runTest {
+ kosmos.testScope.runTest {
setupTestConfiguration(
DeviceConfig.Y_ALIGNED,
rotation = DisplayRotation.ROTATION_0,
isInRearDisplayMode = false
)
- val overlayViewProperties by collectLastValue(underTest.overlayViewProperties)
+ val overlayViewProperties by
+ collectLastValue(kosmos.sideFpsOverlayViewModel.overlayViewProperties)
runCurrent()
- displayStateRepository.setCurrentRotation(DisplayRotation.ROTATION_0)
+ kosmos.displayStateRepository.setCurrentRotation(DisplayRotation.ROTATION_0)
assertThat(overlayViewProperties?.indicatorAsset).isEqualTo(R.raw.sfps_pulse)
assertThat(overlayViewProperties?.overlayViewRotation).isEqualTo(0f)
- displayStateRepository.setCurrentRotation(DisplayRotation.ROTATION_90)
+ kosmos.displayStateRepository.setCurrentRotation(DisplayRotation.ROTATION_90)
assertThat(overlayViewProperties?.indicatorAsset).isEqualTo(R.raw.sfps_pulse_landscape)
assertThat(overlayViewProperties?.overlayViewRotation).isEqualTo(0f)
- displayStateRepository.setCurrentRotation(DisplayRotation.ROTATION_180)
+ kosmos.displayStateRepository.setCurrentRotation(DisplayRotation.ROTATION_180)
assertThat(overlayViewProperties?.indicatorAsset).isEqualTo(R.raw.sfps_pulse)
assertThat(overlayViewProperties?.overlayViewRotation).isEqualTo(180f)
- displayStateRepository.setCurrentRotation(DisplayRotation.ROTATION_270)
+ kosmos.displayStateRepository.setCurrentRotation(DisplayRotation.ROTATION_270)
assertThat(overlayViewProperties?.indicatorAsset).isEqualTo(R.raw.sfps_pulse_landscape)
assertThat(overlayViewProperties?.overlayViewRotation).isEqualTo(180f)
@@ -346,7 +198,7 @@
@Test
fun updatesOverlayViewParams_onDisplayRotationChange_xAlignedSensor() {
- testScope.runTest {
+ kosmos.testScope.runTest {
mSetFlagsRule.disableFlags(FLAG_CONSTRAINT_BP)
setupTestConfiguration(
DeviceConfig.X_ALIGNED,
@@ -354,16 +206,17 @@
isInRearDisplayMode = false
)
- val overlayViewParams by collectLastValue(underTest.overlayViewParams)
+ val overlayViewParams by
+ collectLastValue(kosmos.sideFpsOverlayViewModel.overlayViewParams)
- underTest.setLottieBounds(Rect(0, 0, boundsWidth, boundsHeight))
+ kosmos.sideFpsOverlayViewModel.setLottieBounds(Rect(0, 0, boundsWidth, boundsHeight))
runCurrent()
assertThat(overlayViewParams).isNotNull()
assertThat(overlayViewParams!!.x).isEqualTo(sensorLocation.sensorLocationX)
assertThat(overlayViewParams!!.y).isEqualTo(0)
- displayStateRepository.setCurrentRotation(DisplayRotation.ROTATION_90)
+ kosmos.displayStateRepository.setCurrentRotation(DisplayRotation.ROTATION_90)
assertThat(overlayViewParams).isNotNull()
assertThat(overlayViewParams!!.x).isEqualTo(0)
assertThat(overlayViewParams!!.y)
@@ -371,7 +224,7 @@
displayHeight - sensorLocation.sensorLocationX - sensorLocation.sensorRadius * 2
)
- displayStateRepository.setCurrentRotation(DisplayRotation.ROTATION_180)
+ kosmos.displayStateRepository.setCurrentRotation(DisplayRotation.ROTATION_180)
assertThat(overlayViewParams).isNotNull()
assertThat(overlayViewParams!!.x)
.isEqualTo(
@@ -379,7 +232,7 @@
)
assertThat(overlayViewParams!!.y).isEqualTo(displayHeight - boundsHeight)
- displayStateRepository.setCurrentRotation(DisplayRotation.ROTATION_270)
+ kosmos.displayStateRepository.setCurrentRotation(DisplayRotation.ROTATION_270)
assertThat(overlayViewParams).isNotNull()
assertThat(overlayViewParams!!.x).isEqualTo(displayWidth - boundsWidth)
assertThat(overlayViewParams!!.y).isEqualTo(sensorLocation.sensorLocationX)
@@ -388,7 +241,7 @@
@Test
fun updatesOverlayViewParams_onDisplayRotationChange_yAlignedSensor() {
- testScope.runTest {
+ kosmos.testScope.runTest {
mSetFlagsRule.disableFlags(FLAG_CONSTRAINT_BP)
setupTestConfiguration(
DeviceConfig.Y_ALIGNED,
@@ -396,21 +249,22 @@
isInRearDisplayMode = false
)
- val overlayViewParams by collectLastValue(underTest.overlayViewParams)
+ val overlayViewParams by
+ collectLastValue(kosmos.sideFpsOverlayViewModel.overlayViewParams)
- underTest.setLottieBounds(Rect(0, 0, boundsWidth, boundsHeight))
+ kosmos.sideFpsOverlayViewModel.setLottieBounds(Rect(0, 0, boundsWidth, boundsHeight))
runCurrent()
assertThat(overlayViewParams).isNotNull()
assertThat(overlayViewParams!!.x).isEqualTo(displayWidth - boundsWidth)
assertThat(overlayViewParams!!.y).isEqualTo(sensorLocation.sensorLocationY)
- displayStateRepository.setCurrentRotation(DisplayRotation.ROTATION_90)
+ kosmos.displayStateRepository.setCurrentRotation(DisplayRotation.ROTATION_90)
assertThat(overlayViewParams).isNotNull()
assertThat(overlayViewParams!!.x).isEqualTo(sensorLocation.sensorLocationY)
assertThat(overlayViewParams!!.y).isEqualTo(0)
- displayStateRepository.setCurrentRotation(DisplayRotation.ROTATION_180)
+ kosmos.displayStateRepository.setCurrentRotation(DisplayRotation.ROTATION_180)
assertThat(overlayViewParams).isNotNull()
assertThat(overlayViewParams!!.x).isEqualTo(0)
assertThat(overlayViewParams!!.y)
@@ -418,7 +272,7 @@
displayHeight - sensorLocation.sensorLocationY - sensorLocation.sensorRadius * 2
)
- displayStateRepository.setCurrentRotation(DisplayRotation.ROTATION_270)
+ kosmos.displayStateRepository.setCurrentRotation(DisplayRotation.ROTATION_270)
assertThat(overlayViewParams).isNotNull()
assertThat(overlayViewParams!!.x)
.isEqualTo(
@@ -430,13 +284,13 @@
@Test
fun updatesLottieCallbacks_onShowIndicatorForDeviceEntry() {
- testScope.runTest {
- val lottieCallbacks by collectLastValue(underTest.lottieCallbacks)
+ kosmos.testScope.runTest {
+ val lottieCallbacks by collectLastValue(kosmos.sideFpsOverlayViewModel.lottieCallbacks)
- biometricStatusRepository.setFingerprintAuthenticationReason(
+ kosmos.biometricStatusRepository.setFingerprintAuthenticationReason(
AuthenticationReason.NotRunning
)
- sideFpsProgressBarViewModel.setVisible(false)
+ kosmos.sideFpsProgressBarViewModel.setVisible(false)
updatePrimaryBouncer(
isShowing = true,
@@ -457,14 +311,14 @@
@Test
fun updatesLottieCallbacks_onShowIndicatorForSystemServer_inDarkMode() {
- testScope.runTest {
- val lottieCallbacks by collectLastValue(underTest.lottieCallbacks)
+ kosmos.testScope.runTest {
+ val lottieCallbacks by collectLastValue(kosmos.sideFpsOverlayViewModel.lottieCallbacks)
setDarkMode(true)
- biometricStatusRepository.setFingerprintAuthenticationReason(
+ kosmos.biometricStatusRepository.setFingerprintAuthenticationReason(
AuthenticationReason.BiometricPromptAuthentication
)
- sideFpsProgressBarViewModel.setVisible(false)
+ kosmos.sideFpsProgressBarViewModel.setVisible(false)
updatePrimaryBouncer(
isShowing = false,
@@ -483,14 +337,14 @@
@Test
fun updatesLottieCallbacks_onShowIndicatorForSystemServer_inLightMode() {
- testScope.runTest {
- val lottieCallbacks by collectLastValue(underTest.lottieCallbacks)
+ kosmos.testScope.runTest {
+ val lottieCallbacks by collectLastValue(kosmos.sideFpsOverlayViewModel.lottieCallbacks)
setDarkMode(false)
- biometricStatusRepository.setFingerprintAuthenticationReason(
+ kosmos.biometricStatusRepository.setFingerprintAuthenticationReason(
AuthenticationReason.BiometricPromptAuthentication
)
- sideFpsProgressBarViewModel.setVisible(false)
+ kosmos.sideFpsProgressBarViewModel.setVisible(false)
updatePrimaryBouncer(
isShowing = false,
@@ -526,14 +380,16 @@
fpsDetectionRunning: Boolean,
isUnlockingWithFpAllowed: Boolean,
) {
- bouncerRepository.setPrimaryShow(isShowing)
- bouncerRepository.setPrimaryStartingToHide(false)
+ kosmos.keyguardBouncerRepository.setPrimaryShow(isShowing)
+ kosmos.keyguardBouncerRepository.setPrimaryStartingToHide(false)
val primaryStartDisappearAnimation = if (isAnimatingAway) Runnable {} else null
- bouncerRepository.setPrimaryStartDisappearAnimation(primaryStartDisappearAnimation)
+ kosmos.keyguardBouncerRepository.setPrimaryStartDisappearAnimation(
+ primaryStartDisappearAnimation
+ )
- whenever(keyguardUpdateMonitor.isFingerprintDetectionRunning)
+ whenever(kosmos.keyguardUpdateMonitor.isFingerprintDetectionRunning)
.thenReturn(fpsDetectionRunning)
- whenever(keyguardUpdateMonitor.isUnlockingWithFingerprintAllowed)
+ whenever(kosmos.keyguardUpdateMonitor.isUnlockingWithFingerprintAllowed)
.thenReturn(isUnlockingWithFpAllowed)
mContext.orCreateTestableResources.addOverride(
R.bool.config_show_sidefps_hint_on_bouncer,
@@ -565,7 +421,7 @@
}
}
- whenever(windowManager.maximumWindowMetrics)
+ whenever(kosmos.windowManager.maximumWindowMetrics)
.thenReturn(
WindowMetrics(
Rect(0, 0, displayWidth, displayHeight),
@@ -575,18 +431,17 @@
contextDisplayInfo.uniqueId = DISPLAY_ID
- fingerprintPropertyRepository.setProperties(
+ kosmos.fingerprintPropertyRepository.setProperties(
sensorId = 1,
strength = SensorStrength.STRONG,
sensorType = FingerprintSensorType.POWER_BUTTON,
sensorLocations = mapOf(DISPLAY_ID to sensorLocation)
)
- displayStateRepository.setIsInRearDisplayMode(isInRearDisplayMode)
+ kosmos.displayStateRepository.setIsInRearDisplayMode(isInRearDisplayMode)
+ kosmos.displayStateRepository.setCurrentRotation(rotation)
- displayStateRepository.setCurrentRotation(rotation)
-
- displayRepository.emitDisplayChangeEvent(0)
+ kosmos.displayRepository.emitDisplayChangeEvent(0)
runCurrent()
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingCollectorImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingCollectorImplTest.java
index 8e5ddc7..bc6c459 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingCollectorImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingCollectorImplTest.java
@@ -50,6 +50,8 @@
import com.android.systemui.util.sensors.ThresholdSensor;
import com.android.systemui.util.time.FakeSystemClock;
+import kotlinx.coroutines.flow.StateFlowKt;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -58,8 +60,6 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import kotlinx.coroutines.flow.StateFlowKt;
-
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayUtilsTest.java b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayUtilsTest.java
index db85522..63e43d7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayUtilsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayUtilsTest.java
@@ -39,8 +39,8 @@
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
-import com.android.systemui.res.R;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.res.R;
import com.google.android.collect.Lists;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/IntentCreatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/IntentCreatorTest.java
index fb07e6e..ea6cb3b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/IntentCreatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/IntentCreatorTest.java
@@ -28,8 +28,8 @@
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
-import com.android.systemui.res.R;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.res.R;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/common/ui/view/SeekBarWithIconButtonsViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/common/ui/view/SeekBarWithIconButtonsViewTest.java
index 98f7f59..4c4205e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/common/ui/view/SeekBarWithIconButtonsViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/common/ui/view/SeekBarWithIconButtonsViewTest.java
@@ -33,9 +33,9 @@
import androidx.test.filters.SmallTest;
-import com.android.systemui.res.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.common.ui.view.SeekBarWithIconButtonsView.OnSeekBarWithIconButtonsChangeListener;
+import com.android.systemui.res.R;
import org.junit.Before;
import org.junit.Test;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/complication/ComplicationLayoutEngineTest.java b/packages/SystemUI/tests/src/com/android/systemui/complication/ComplicationLayoutEngineTest.java
index a78f0b7..baaeee1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/complication/ComplicationLayoutEngineTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/complication/ComplicationLayoutEngineTest.java
@@ -28,9 +28,9 @@
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.test.filters.SmallTest;
-import com.android.systemui.res.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.complication.ComplicationLayoutEngine.Margins;
+import com.android.systemui.res.R;
import com.android.systemui.touch.TouchInsetManager;
import org.junit.Before;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/complication/ComplicationUtilsTest.java b/packages/SystemUI/tests/src/com/android/systemui/complication/ComplicationUtilsTest.java
index 235c56b..e23e1f4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/complication/ComplicationUtilsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/complication/ComplicationUtilsTest.java
@@ -27,7 +27,6 @@
import static com.android.systemui.complication.ComplicationUtils.convertComplicationType;
import static com.android.systemui.complication.ComplicationUtils.convertComplicationTypes;
-
import static com.google.common.truth.Truth.assertThat;
import android.testing.AndroidTestingRunner;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/AlwaysOnDisplayPolicyTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/AlwaysOnDisplayPolicyTest.java
index ea7467f..e1dc696 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/AlwaysOnDisplayPolicyTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/AlwaysOnDisplayPolicyTest.java
@@ -24,8 +24,8 @@
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
-import com.android.systemui.res.R;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.res.R;
import org.junit.After;
import org.junit.Before;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSuppressorTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSuppressorTest.java
index 9064470..92941f9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSuppressorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSuppressorTest.java
@@ -47,6 +47,8 @@
import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.phone.BiometricUnlockController;
+import dagger.Lazy;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -57,8 +59,6 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import dagger.Lazy;
-
@SmallTest
@RunWith(AndroidTestingRunner.class)
@UiThreadTest
diff --git a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsColumnLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsColumnLayoutTest.java
index f89a0b6..f4fadaa 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsColumnLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsColumnLayoutTest.java
@@ -30,8 +30,8 @@
import androidx.test.filters.SmallTest;
-import com.android.systemui.res.R;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.res.R;
import com.android.systemui.util.leak.RotationUtils;
import org.junit.Before;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsGridLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsGridLayoutTest.java
index 5a97b74..84b1c00 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsGridLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsGridLayoutTest.java
@@ -28,8 +28,8 @@
import androidx.test.filters.SmallTest;
-import com.android.systemui.res.R;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.res.R;
import com.android.systemui.util.leak.RotationUtils;
import org.junit.Before;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/globalactions/ListGridLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/globalactions/ListGridLayoutTest.java
index a003e07..4c65b90 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/globalactions/ListGridLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/globalactions/ListGridLayoutTest.java
@@ -25,8 +25,8 @@
import androidx.test.filters.SmallTest;
-import com.android.systemui.res.R;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.res.R;
import org.junit.Before;
import org.junit.Test;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/globalactions/ShutdownUiTest.java b/packages/SystemUI/tests/src/com/android/systemui/globalactions/ShutdownUiTest.java
index 2d3ca60..28c01ad 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/globalactions/ShutdownUiTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/globalactions/ShutdownUiTest.java
@@ -40,7 +40,6 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-
@SmallTest
@RunWith(AndroidTestingRunner.class)
public class ShutdownUiTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
index 709f779..59f7d61 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
@@ -133,6 +133,10 @@
import com.android.systemui.wallpapers.data.repository.FakeWallpaperRepository;
import com.android.wm.shell.keyguard.KeyguardTransitions;
+import kotlinx.coroutines.CoroutineDispatcher;
+import kotlinx.coroutines.flow.Flow;
+import kotlinx.coroutines.test.TestScope;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -143,10 +147,6 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import kotlinx.coroutines.CoroutineDispatcher;
-import kotlinx.coroutines.flow.Flow;
-import kotlinx.coroutines.test.TestScope;
-
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@SmallTest
diff --git a/packages/SystemUI/tests/src/com/android/systemui/logcat/LogAccessDialogActivityTest.java b/packages/SystemUI/tests/src/com/android/systemui/logcat/LogAccessDialogActivityTest.java
index eed7ecd..aef05a7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/logcat/LogAccessDialogActivityTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/logcat/LogAccessDialogActivityTest.java
@@ -31,8 +31,8 @@
import androidx.test.platform.app.InstrumentationRegistry;
import com.android.internal.app.ILogAccessDialogCallback;
-import com.android.systemui.res.R;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.res.R;
import org.junit.Before;
import org.junit.Rule;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java
index 2f057a2..95e34a9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java
@@ -46,8 +46,8 @@
import com.android.settingslib.media.LocalMediaManager;
import com.android.settingslib.media.MediaDevice;
-import com.android.systemui.res.R;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.res.R;
import com.google.common.collect.ImmutableList;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/systemsounds/HomeSoundEffectControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/systemsounds/HomeSoundEffectControllerTest.java
index 33a30e0..293f66b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/systemsounds/HomeSoundEffectControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/systemsounds/HomeSoundEffectControllerTest.java
@@ -45,7 +45,6 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-
@SmallTest
@RunWith(AndroidJUnit4.class)
public class HomeSoundEffectControllerTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/people/PeopleSpaceUtilsTest.java b/packages/SystemUI/tests/src/com/android/systemui/people/PeopleSpaceUtilsTest.java
index 30d66dc..84a8ab0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/people/PeopleSpaceUtilsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/people/PeopleSpaceUtilsTest.java
@@ -58,10 +58,10 @@
import androidx.test.filters.SmallTest;
import com.android.internal.appwidget.IAppWidgetService;
-import com.android.systemui.res.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.people.widget.PeopleSpaceWidgetManager;
import com.android.systemui.people.widget.PeopleTileKey;
+import com.android.systemui.res.R;
import com.android.systemui.statusbar.NotificationListener;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/people/PeopleTileViewHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/people/PeopleTileViewHelperTest.java
index d0e8cce..3d1da00 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/people/PeopleTileViewHelperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/people/PeopleTileViewHelperTest.java
@@ -60,9 +60,9 @@
import androidx.test.filters.SmallTest;
-import com.android.systemui.res.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.people.widget.PeopleTileKey;
+import com.android.systemui.res.R;
import org.junit.Before;
import org.junit.Test;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/process/condition/SystemProcessConditionTest.java b/packages/SystemUI/tests/src/com/android/systemui/process/condition/SystemProcessConditionTest.java
index ff60fcd..f573358 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/process/condition/SystemProcessConditionTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/process/condition/SystemProcessConditionTest.java
@@ -31,14 +31,14 @@
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.time.FakeSystemClock;
+import kotlinx.coroutines.CoroutineScope;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import kotlinx.coroutines.CoroutineScope;
-
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@SmallTest
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterViewControllerTest.java
index 98e803f..5ae0c24 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterViewControllerTest.java
@@ -34,9 +34,9 @@
import androidx.test.filters.SmallTest;
-import com.android.systemui.res.R;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.FalsingManager;
+import com.android.systemui.res.R;
import com.android.systemui.retail.data.repository.FakeRetailModeRepository;
import com.android.systemui.retail.domain.interactor.RetailModeInteractorImpl;
import com.android.systemui.settings.UserTracker;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java
index d3cd26b..df0ab34 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java
@@ -50,10 +50,10 @@
import androidx.test.filters.SmallTest;
import com.android.internal.logging.InstanceId;
-import com.android.systemui.res.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.plugins.qs.QSTile;
import com.android.systemui.qs.QSHost;
+import com.android.systemui.res.R;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.time.FakeSystemClock;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
index 248af1e..b62d59d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
@@ -47,7 +47,7 @@
import com.android.systemui.qs.pipeline.domain.interactor.PanelInteractor;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.phone.StatusBarIconController;
+import com.android.systemui.statusbar.phone.ui.StatusBarIconController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.concurrency.DelayableExecutor;
import com.android.systemui.util.concurrency.FakeExecutor;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java
index efbfb4f..46ee569 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java
@@ -60,6 +60,8 @@
import com.android.systemui.statusbar.policy.HotspotController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
+import kotlinx.coroutines.test.TestScope;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -71,8 +73,6 @@
import java.util.ArrayList;
import java.util.List;
-import kotlinx.coroutines.test.TestScope;
-
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
@SmallTest
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ColorInversionTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ColorInversionTileTest.java
index c93ff4b..ea43326 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ColorInversionTileTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ColorInversionTileTest.java
@@ -32,7 +32,6 @@
import androidx.test.filters.SmallTest;
import com.android.internal.logging.MetricsLogger;
-import com.android.systemui.res.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.classifier.FalsingManagerFake;
import com.android.systemui.plugins.ActivityStarter;
@@ -42,6 +41,7 @@
import com.android.systemui.qs.QsEventLogger;
import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.qs.tileimpl.QSTileImpl;
+import com.android.systemui.res.R;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.util.settings.FakeSettings;
import com.android.systemui.util.settings.SecureSettings;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DreamTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DreamTileTest.java
index 954d30ed..a3c2975 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DreamTileTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DreamTileTest.java
@@ -41,7 +41,6 @@
import androidx.test.filters.SmallTest;
import com.android.internal.logging.MetricsLogger;
-import com.android.systemui.res.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.classifier.FalsingManagerFake;
@@ -51,6 +50,7 @@
import com.android.systemui.qs.QsEventLogger;
import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.qs.tileimpl.QSTileImpl;
+import com.android.systemui.res.R;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.util.settings.FakeSettings;
import com.android.systemui.util.settings.SecureSettings;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/HotspotTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/HotspotTileTest.java
index 14dfdea..a85b49b6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/HotspotTileTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/HotspotTileTest.java
@@ -31,7 +31,6 @@
import com.android.dx.mockito.inline.extended.ExtendedMockito;
import com.android.internal.logging.MetricsLogger;
import com.android.settingslib.wifi.WifiEnterpriseRestrictionUtils;
-import com.android.systemui.res.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.classifier.FalsingManagerFake;
import com.android.systemui.plugins.ActivityStarter;
@@ -41,6 +40,7 @@
import com.android.systemui.qs.QsEventLogger;
import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.qs.tileimpl.QSTileImpl;
+import com.android.systemui.res.R;
import com.android.systemui.statusbar.policy.DataSaverController;
import com.android.systemui.statusbar.policy.HotspotController;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/InternetTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/InternetTileTest.java
index 288facc..0ea61f9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/InternetTileTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/InternetTileTest.java
@@ -17,6 +17,7 @@
package com.android.systemui.qs.tiles;
import static com.google.common.truth.Truth.assertThat;
+
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@@ -28,7 +29,6 @@
import androidx.test.filters.SmallTest;
import com.android.internal.logging.MetricsLogger;
-import com.android.systemui.res.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.classifier.FalsingManagerFake;
import com.android.systemui.plugins.ActivityStarter;
@@ -38,6 +38,7 @@
import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.qs.tileimpl.QSTileImpl;
import com.android.systemui.qs.tiles.dialog.InternetDialogManager;
+import com.android.systemui.res.R;
import com.android.systemui.statusbar.connectivity.AccessPointController;
import com.android.systemui.statusbar.connectivity.IconState;
import com.android.systemui.statusbar.connectivity.NetworkController;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/NfcTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/NfcTileTest.java
index 118ad2c..f6bc692 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/NfcTileTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/NfcTileTest.java
@@ -30,7 +30,6 @@
import androidx.test.filters.SmallTest;
import com.android.internal.logging.MetricsLogger;
-import com.android.systemui.res.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.classifier.FalsingManagerFake;
@@ -39,6 +38,7 @@
import com.android.systemui.qs.QSHost;
import com.android.systemui.qs.QsEventLogger;
import com.android.systemui.qs.logging.QSLogger;
+import com.android.systemui.res.R;
import org.junit.After;
import org.junit.Before;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QRCodeScannerTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QRCodeScannerTileTest.java
index 7b3171d..d7beb5d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QRCodeScannerTileTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QRCodeScannerTileTest.java
@@ -30,7 +30,6 @@
import androidx.test.filters.SmallTest;
import com.android.internal.logging.MetricsLogger;
-import com.android.systemui.res.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.classifier.FalsingManagerFake;
import com.android.systemui.plugins.ActivityStarter;
@@ -41,6 +40,7 @@
import com.android.systemui.qs.QsEventLogger;
import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.qs.tileimpl.QSTileImpl;
+import com.android.systemui.res.R;
import org.junit.After;
import org.junit.Before;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ReduceBrightColorsTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ReduceBrightColorsTileTest.java
index c5721ff..8eaa876 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ReduceBrightColorsTileTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ReduceBrightColorsTileTest.java
@@ -32,7 +32,6 @@
import com.android.internal.R;
import com.android.internal.logging.MetricsLogger;
-import com.android.systemui.res.R.drawable;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.classifier.FalsingManagerFake;
import com.android.systemui.plugins.ActivityStarter;
@@ -43,6 +42,7 @@
import com.android.systemui.qs.ReduceBrightColorsController;
import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.qs.tileimpl.QSTileImpl;
+import com.android.systemui.res.R.drawable;
import com.android.systemui.settings.UserTracker;
import org.junit.After;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegateControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegateControllerTest.java
index b384fe8..2536a93 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegateControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegateControllerTest.java
@@ -5,6 +5,7 @@
import static android.telephony.SignalStrength.NUM_SIGNAL_STRENGTH_BINS;
import static android.telephony.SignalStrength.SIGNAL_STRENGTH_GREAT;
import static android.telephony.SignalStrength.SIGNAL_STRENGTH_POOR;
+
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
import static com.android.settingslib.wifi.WifiUtils.getHotspotIconResource;
import static com.android.systemui.qs.tiles.dialog.InternetDialogController.TOAST_PARAMS_HORIZONTAL_WEIGHT;
@@ -12,7 +13,9 @@
import static com.android.wifitrackerlib.WifiEntry.WIFI_LEVEL_MAX;
import static com.android.wifitrackerlib.WifiEntry.WIFI_LEVEL_MIN;
import static com.android.wifitrackerlib.WifiEntry.WIFI_LEVEL_UNREACHABLE;
+
import static com.google.common.truth.Truth.assertThat;
+
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingControllerTest.java
index 9e559de..2444af7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingControllerTest.java
@@ -17,9 +17,12 @@
package com.android.systemui.screenrecord;
import static android.os.Process.myUid;
+
import static com.google.common.truth.Truth.assertThat;
+
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
+
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/WorkProfileMessageControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/WorkProfileMessageControllerTest.java
index 10bd6af..4b7d5f0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/WorkProfileMessageControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/WorkProfileMessageControllerTest.java
@@ -38,10 +38,12 @@
import androidx.test.filters.SmallTest;
-import com.android.systemui.res.R;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.res.R;
import com.android.systemui.util.FakeSharedPreferences;
+import kotlin.Unit;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -51,9 +53,6 @@
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
-import kotlin.Unit;
-
-
@SmallTest
@RunWith(AndroidTestingRunner.class)
public class WorkProfileMessageControllerTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsActivityTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsActivityTest.java
index 2c7b606..68a6893 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsActivityTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsActivityTest.java
@@ -47,8 +47,8 @@
import androidx.test.runner.intercepting.SingleActivityFactory;
import com.android.internal.logging.UiEventLogger;
-import com.android.systemui.res.R;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.res.R;
import com.android.systemui.screenshot.ImageExporter;
import com.android.systemui.settings.UserTracker;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsTrampolineActivityTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsTrampolineActivityTest.java
index 3d55527..6733ead 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsTrampolineActivityTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsTrampolineActivityTest.java
@@ -57,12 +57,12 @@
import com.android.internal.infra.ServiceConnector;
import com.android.internal.logging.UiEventLogger;
import com.android.internal.statusbar.IAppClipsService;
-import com.android.systemui.res.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.broadcast.BroadcastSender;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.notetask.NoteTaskController;
+import com.android.systemui.res.R;
import com.google.common.util.concurrent.MoreExecutors;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt
index 03f5ecf..7b5c1d3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt
@@ -16,14 +16,13 @@
package com.android.systemui.shade
-import android.content.Context
+import android.graphics.Rect
import android.os.PowerManager
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.testing.ViewUtils
import android.view.MotionEvent
import android.view.View
-import android.view.WindowManager
import android.widget.FrameLayout
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
@@ -132,6 +131,11 @@
testableLooper = TestableLooper.get(this)
overrideResource(R.dimen.communal_right_edge_swipe_region_width, RIGHT_SWIPE_REGION_WIDTH)
+ overrideResource(R.dimen.communal_top_edge_swipe_region_height, TOP_SWIPE_REGION_WIDTH)
+ overrideResource(
+ R.dimen.communal_bottom_edge_swipe_region_height,
+ BOTTOM_SWIPE_REGION_WIDTH
+ )
// Make communal available so that communalInteractor.desiredScene accurately reflects
// scene changes instead of just returning Blank.
@@ -421,6 +425,24 @@
}
}
+ @Test
+ fun gestureExclusionZone_setAfterInit() =
+ with(kosmos) {
+ testScope.runTest {
+ goToScene(CommunalScenes.Communal)
+
+ assertThat(containerView.systemGestureExclusionRects)
+ .containsExactly(
+ Rect(
+ /* left */ 0,
+ /* top */ TOP_SWIPE_REGION_WIDTH,
+ /* right */ CONTAINER_WIDTH,
+ /* bottom */ CONTAINER_HEIGHT - BOTTOM_SWIPE_REGION_WIDTH
+ )
+ )
+ }
+ }
+
private fun initAndAttachContainerView() {
containerView = View(context)
@@ -430,18 +452,9 @@
underTest.initView(containerView)
// Attach the view so that flows start collecting.
- ViewUtils.attachView(parentView)
+ ViewUtils.attachView(parentView, CONTAINER_WIDTH, CONTAINER_HEIGHT)
// Attaching is async so processAllMessages is required for view.repeatWhenAttached to run.
testableLooper.processAllMessages()
-
- // Give the view a fixed size to simplify testing for edge swipes.
- val lp =
- parentView.layoutParams.apply {
- width = CONTAINER_WIDTH
- height = CONTAINER_HEIGHT
- }
- val wm = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
- wm.updateViewLayout(parentView, lp)
}
private fun goToScene(scene: SceneKey) {
@@ -453,6 +466,8 @@
private const val CONTAINER_WIDTH = 100
private const val CONTAINER_HEIGHT = 100
private const val RIGHT_SWIPE_REGION_WIDTH = 20
+ private const val TOP_SWIPE_REGION_WIDTH = 12
+ private const val BOTTOM_SWIPE_REGION_WIDTH = 14
/**
* A touch down event right in the middle of the screen, to avoid being in any of the swipe
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
index d5e88fe..3793970 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
@@ -23,6 +23,9 @@
import static com.google.common.truth.Truth.assertThat;
+import static kotlinx.coroutines.flow.FlowKt.emptyFlow;
+import static kotlinx.coroutines.flow.StateFlowKt.MutableStateFlow;
+
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyFloat;
@@ -37,9 +40,6 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import static kotlinx.coroutines.flow.FlowKt.emptyFlow;
-import static kotlinx.coroutines.flow.StateFlowKt.MutableStateFlow;
-
import android.annotation.IdRes;
import android.content.ContentResolver;
import android.content.res.Configuration;
@@ -202,6 +202,9 @@
import dagger.Lazy;
+import kotlinx.coroutines.CoroutineDispatcher;
+import kotlinx.coroutines.test.TestScope;
+
import org.junit.After;
import org.junit.Before;
import org.mockito.ArgumentCaptor;
@@ -213,9 +216,6 @@
import java.util.List;
import java.util.Optional;
-import kotlinx.coroutines.CoroutineDispatcher;
-import kotlinx.coroutines.test.TestScope;
-
public class NotificationPanelViewControllerBaseTest extends SysuiTestCase {
protected static final int SPLIT_SHADE_FULL_TRANSITION_DISTANCE = 400;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerImplBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerImplBaseTest.java
index 0f51878..317e35c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerImplBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerImplBaseTest.java
@@ -16,14 +16,14 @@
package com.android.systemui.shade;
+import static kotlinx.coroutines.flow.StateFlowKt.MutableStateFlow;
+import static kotlinx.coroutines.test.TestCoroutineDispatchersKt.StandardTestDispatcher;
+
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
-import static kotlinx.coroutines.flow.StateFlowKt.MutableStateFlow;
-import static kotlinx.coroutines.test.TestCoroutineDispatchersKt.StandardTestDispatcher;
-
import android.content.res.Resources;
import android.os.Handler;
import android.os.Looper;
@@ -98,13 +98,13 @@
import dagger.Lazy;
+import kotlinx.coroutines.test.TestScope;
+
import org.junit.After;
import org.junit.Before;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import kotlinx.coroutines.test.TestScope;
-
public class QuickSettingsControllerImplBaseTest extends SysuiTestCase {
protected static final float QS_FRAME_START_X = 0f;
protected static final int QS_FRAME_WIDTH = 1000;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeHeaderControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeHeaderControllerTest.kt
index 9fa173a..0846ced 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeHeaderControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeHeaderControllerTest.kt
@@ -22,6 +22,7 @@
import android.content.Context
import android.content.res.Resources
import android.content.res.XmlResourceParser
+import android.graphics.Insets
import android.graphics.Rect
import android.testing.AndroidTestingRunner
import android.view.Display
@@ -35,7 +36,6 @@
import androidx.constraintlayout.widget.ConstraintSet
import androidx.test.filters.SmallTest
import com.android.app.animation.Interpolators
-import com.android.systemui.res.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.animation.ShadeInterpolation
import com.android.systemui.battery.BatteryMeterView
@@ -46,6 +46,7 @@
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.qs.ChipVisibilityListener
import com.android.systemui.qs.HeaderPrivacyIconsController
+import com.android.systemui.res.R
import com.android.systemui.shade.ShadeHeaderController.Companion.DEFAULT_CLOCK_INTENT
import com.android.systemui.shade.ShadeHeaderController.Companion.LARGE_SCREEN_HEADER_CONSTRAINT
import com.android.systemui.shade.ShadeHeaderController.Companion.QQS_HEADER_CONSTRAINT
@@ -53,9 +54,10 @@
import com.android.systemui.shade.carrier.ShadeCarrierGroup
import com.android.systemui.shade.carrier.ShadeCarrierGroupController
import com.android.systemui.statusbar.phone.StatusBarContentInsetsProvider
-import com.android.systemui.statusbar.phone.StatusBarIconController
import com.android.systemui.statusbar.phone.StatusIconContainer
import com.android.systemui.statusbar.phone.StatusOverlayHoverListenerFactory
+import com.android.systemui.statusbar.phone.ui.StatusBarIconController
+import com.android.systemui.statusbar.phone.ui.TintedIconManager
import com.android.systemui.statusbar.policy.Clock
import com.android.systemui.statusbar.policy.FakeConfigurationController
import com.android.systemui.statusbar.policy.NextAlarmController
@@ -83,7 +85,6 @@
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
import org.mockito.Mockito.`when` as whenever
-import android.graphics.Insets
import org.mockito.junit.MockitoJUnit
private val EMPTY_CHANGES = ConstraintsChanges()
@@ -95,8 +96,8 @@
@Mock(answer = Answers.RETURNS_MOCKS) private lateinit var view: MotionLayout
@Mock private lateinit var statusIcons: StatusIconContainer
@Mock private lateinit var statusBarIconController: StatusBarIconController
- @Mock private lateinit var iconManagerFactory: StatusBarIconController.TintedIconManager.Factory
- @Mock private lateinit var iconManager: StatusBarIconController.TintedIconManager
+ @Mock private lateinit var iconManagerFactory: TintedIconManager.Factory
+ @Mock private lateinit var iconManager: TintedIconManager
@Mock private lateinit var mShadeCarrierGroupController: ShadeCarrierGroupController
@Mock
private lateinit var mShadeCarrierGroupControllerBuilder: ShadeCarrierGroupController.Builder
@@ -145,12 +146,14 @@
whenever<TextView>(view.requireViewById(R.id.date)).thenReturn(date)
whenever(date.context).thenReturn(mockedContext)
- whenever<ShadeCarrierGroup>(view.requireViewById(R.id.carrier_group)).thenReturn(carrierGroup)
+ whenever<ShadeCarrierGroup>(view.requireViewById(R.id.carrier_group))
+ .thenReturn(carrierGroup)
whenever<BatteryMeterView>(view.requireViewById(R.id.batteryRemainingIcon))
.thenReturn(batteryMeterView)
- whenever<StatusIconContainer>(view.requireViewById(R.id.statusIcons)).thenReturn(statusIcons)
+ whenever<StatusIconContainer>(view.requireViewById(R.id.statusIcons))
+ .thenReturn(statusIcons)
whenever<View>(view.requireViewById(R.id.hover_system_icons_container))
.thenReturn(systemIconsHoverContainer)
@@ -933,14 +936,14 @@
private fun mockInsetsProvider(insets: Pair<Int, Int> = 0 to 0, cornerCutout: Boolean = false) {
whenever(insetsProvider.getStatusBarContentInsetsForCurrentRotation())
- .thenReturn(
- Insets.of(
- /* left= */ insets.first,
- /* top= */ 0,
- /* right= */ insets.second,
- /* bottom= */ 0
- )
+ .thenReturn(
+ Insets.of(
+ /* left= */ insets.first,
+ /* top= */ 0,
+ /* right= */ insets.second,
+ /* bottom= */ 0
)
+ )
whenever(insetsProvider.currentRotationHasCornerCutout()).thenReturn(cornerCutout)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/carrier/ShadeCarrierGroupControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/carrier/ShadeCarrierGroupControllerTest.java
index e7056c7..4c2d908 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/carrier/ShadeCarrierGroupControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/carrier/ShadeCarrierGroupControllerTest.java
@@ -62,6 +62,8 @@
import com.android.systemui.utils.leaks.LeakCheckedTest;
import com.android.systemui.utils.os.FakeHandler;
+import kotlinx.coroutines.flow.MutableStateFlow;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -73,8 +75,6 @@
import java.util.Arrays;
import java.util.List;
-import kotlinx.coroutines.flow.MutableStateFlow;
-
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@SmallTest
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/carrier/ShadeCarrierTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/carrier/ShadeCarrierTest.java
index a657edf..a42121a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/carrier/ShadeCarrierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/carrier/ShadeCarrierTest.java
@@ -31,8 +31,8 @@
import androidx.test.filters.SmallTest;
import com.android.settingslib.mobile.TelephonyIcons;
-import com.android.systemui.res.R;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.res.R;
import org.junit.Before;
import org.junit.Test;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/condition/ConditionMonitorTest.java b/packages/SystemUI/tests/src/com/android/systemui/shared/condition/ConditionMonitorTest.java
index 0b1753f..65ca0a2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/condition/ConditionMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/condition/ConditionMonitorTest.java
@@ -36,6 +36,8 @@
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.time.FakeSystemClock;
+import kotlinx.coroutines.CoroutineScope;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -48,8 +50,6 @@
import java.util.Collections;
import java.util.HashSet;
-import kotlinx.coroutines.CoroutineScope;
-
@SmallTest
@RunWith(AndroidTestingRunner.class)
public class ConditionMonitorTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/condition/ConditionTest.java b/packages/SystemUI/tests/src/com/android/systemui/shared/condition/ConditionTest.java
index 6efade9..cec5d0a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/condition/ConditionTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/condition/ConditionTest.java
@@ -31,14 +31,14 @@
import com.android.systemui.SysuiTestCase;
+import kotlinx.coroutines.CoroutineScope;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import kotlinx.coroutines.CoroutineScope;
-
@SmallTest
@RunWith(AndroidTestingRunner.class)
public class ConditionTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java
index 544860e..775dc3c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java
@@ -36,9 +36,9 @@
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.statusbar.IStatusBarService;
-import com.android.systemui.res.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.res.R;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/DynamicChildBindControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/DynamicChildBindControllerTest.java
index eafa78e..0103564 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/DynamicChildBindControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/DynamicChildBindControllerTest.java
@@ -55,7 +55,6 @@
import java.util.List;
import java.util.Map;
-
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DeviceProvisionedCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DeviceProvisionedCoordinatorTest.java
index af52459..3676a3d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DeviceProvisionedCoordinatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DeviceProvisionedCoordinatorTest.java
@@ -27,7 +27,6 @@
import android.app.ActivityManagerInternal;
import android.app.Notification;
import android.content.pm.IPackageManager;
-import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.RemoteException;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinatorTest.java
index 6f0a19d..50ae985 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinatorTest.java
@@ -20,6 +20,8 @@
import static junit.framework.Assert.assertFalse;
+import static kotlinx.coroutines.flow.StateFlowKt.MutableStateFlow;
+
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
@@ -29,8 +31,6 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import static kotlinx.coroutines.flow.StateFlowKt.MutableStateFlow;
-
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
@@ -62,6 +62,9 @@
import com.android.systemui.util.kotlin.JavaAdapter;
import com.android.systemui.util.time.FakeSystemClock;
+import kotlinx.coroutines.flow.MutableStateFlow;
+import kotlinx.coroutines.test.TestScope;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -71,9 +74,6 @@
import org.mockito.MockitoAnnotations;
import org.mockito.verification.VerificationMode;
-import kotlinx.coroutines.flow.MutableStateFlow;
-import kotlinx.coroutines.test.TestScope;
-
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterViewTest.java
index 6bda4d4..a21ca94 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterViewTest.java
@@ -50,11 +50,11 @@
import org.junit.Test;
import org.junit.runner.RunWith;
-import java.util.List;
-
import platform.test.runner.parameterized.ParameterizedAndroidJunit4;
import platform.test.runner.parameterized.Parameters;
+import java.util.List;
+
@SmallTest
@RunWith(ParameterizedAndroidJunit4.class)
public class FooterViewTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/KeyguardNotificationVisibilityProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/KeyguardNotificationVisibilityProviderTest.java
index 06410cd..8662048 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/KeyguardNotificationVisibilityProviderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/KeyguardNotificationVisibilityProviderTest.java
@@ -55,7 +55,6 @@
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.flags.FakeFeatureFlagsClassic;
import com.android.systemui.flags.FeatureFlagsClassic;
-import com.android.systemui.flags.Flags;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
index bb68ec5..1113091 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
@@ -16,6 +16,8 @@
package com.android.systemui.statusbar.notification.logging;
+import static kotlinx.coroutines.test.TestCoroutineDispatchersKt.StandardTestDispatcher;
+
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -28,8 +30,6 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import static kotlinx.coroutines.test.TestCoroutineDispatchersKt.StandardTestDispatcher;
-
import android.app.Notification;
import android.os.Handler;
import android.os.Looper;
@@ -72,6 +72,8 @@
import com.google.android.collect.Lists;
+import kotlinx.coroutines.test.TestScope;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -84,8 +86,6 @@
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.Executor;
-import kotlinx.coroutines.test.TestScope;
-
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragControllerTest.java
index bdc8135..9d2f32d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragControllerTest.java
@@ -47,7 +47,6 @@
import org.junit.Test;
import org.junit.runner.RunWith;
-
@SmallTest
@RunWith(AndroidTestingRunner.class)
@RunWithLooper
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java
index 8c22511..03a8403 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java
@@ -95,6 +95,7 @@
@Mock private InflatedSmartReplyState mInflatedSmartReplyState;
@Mock private InflatedSmartReplyViewHolder mInflatedSmartReplies;
@Mock private NotifLayoutInflaterFactory.Provider mNotifLayoutInflaterFactoryProvider;
+ @Mock private HeadsUpStyleProvider mHeadsUpStyleProvider;
@Mock private NotifLayoutInflaterFactory mNotifLayoutInflaterFactory;
private final SmartReplyStateInflater mSmartReplyStateInflater =
@@ -138,6 +139,7 @@
mock(Executor.class),
mSmartReplyStateInflater,
mNotifLayoutInflaterFactoryProvider,
+ mHeadsUpStyleProvider,
mock(NotificationContentInflaterLogger.class));
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
index 9e2856d..907649b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
@@ -28,6 +28,8 @@
import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertTrue;
+import static kotlinx.coroutines.test.TestCoroutineDispatchersKt.StandardTestDispatcher;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
@@ -42,8 +44,6 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import static kotlinx.coroutines.test.TestCoroutineDispatchersKt.StandardTestDispatcher;
-
import android.app.INotificationManager;
import android.app.Notification;
import android.app.NotificationChannel;
@@ -98,6 +98,8 @@
import com.android.systemui.util.kotlin.JavaAdapter;
import com.android.systemui.wmshell.BubblesManager;
+import kotlinx.coroutines.test.TestScope;
+
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -109,8 +111,6 @@
import java.util.Optional;
-import kotlinx.coroutines.test.TestScope;
-
/**
* Tests for {@link NotificationGutsManager}.
*/
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolverTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolverTest.java
index edf2b4c..180c8c8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolverTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolverTest.java
@@ -18,8 +18,6 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertNotSame;
-import static org.junit.Assert.assertSame;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
@@ -37,8 +35,6 @@
import org.junit.Test;
import org.junit.runner.RunWith;
-import java.io.IOException;
-
@SmallTest
@RunWith(AndroidJUnit4.class)
public class NotificationInlineImageResolverTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
index 954335e..1661860 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
@@ -99,6 +99,10 @@
import com.android.systemui.wmshell.BubblesManager;
import com.android.systemui.wmshell.BubblesTestActivity;
+import kotlin.coroutines.CoroutineContext;
+
+import kotlinx.coroutines.test.TestScope;
+
import org.mockito.ArgumentCaptor;
import java.util.Objects;
@@ -107,9 +111,6 @@
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
-import kotlin.coroutines.CoroutineContext;
-import kotlinx.coroutines.test.TestScope;
-
/**
* A helper class to create {@link ExpandableNotificationRow} (for both individual and group
* notifications).
@@ -199,6 +200,7 @@
mock(Executor.class),
new MockSmartReplyInflater(),
mock(NotifLayoutInflaterFactory.Provider.class),
+ mock(HeadsUpStyleProvider.class),
mock(NotificationContentInflaterLogger.class));
contentBinder.setInflateSynchronously(true);
mBindStage = new RowContentBindStage(contentBinder,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapperTest.java
index e3a77d3..fad85f53 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapperTest.java
@@ -21,8 +21,6 @@
import android.content.Context;
import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
-import android.testing.TestableLooper.RunWithLooper;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/AmbientStateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/AmbientStateTest.kt
index 4715b33..fb15948 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/AmbientStateTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/AmbientStateTest.kt
@@ -23,6 +23,7 @@
import com.android.systemui.shade.transition.LargeScreenShadeInterpolator
import com.android.systemui.statusbar.StatusBarState
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
+import com.android.systemui.statusbar.policy.AvalancheController
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
@@ -41,6 +42,7 @@
private val bypassController = StackScrollAlgorithm.BypassController { false }
private val statusBarKeyguardViewManager = mock<StatusBarKeyguardViewManager>()
private val largeScreenShadeInterpolator = mock<LargeScreenShadeInterpolator>()
+ private val avalancheController = mock<AvalancheController>()
private lateinit var sut: AmbientState
@@ -53,7 +55,8 @@
sectionProvider,
bypassController,
statusBarKeyguardViewManager,
- largeScreenShadeInterpolator
+ largeScreenShadeInterpolator,
+ avalancheController
)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
index 89ae9f4..939d055 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
@@ -94,6 +94,7 @@
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.ScreenOffAnimationController;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
+import com.android.systemui.statusbar.policy.AvalancheController;
import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController;
import org.junit.Assert;
@@ -140,6 +141,7 @@
@Mock private NotificationStackSizeCalculator mNotificationStackSizeCalculator;
@Mock private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
@Mock private LargeScreenShadeInterpolator mLargeScreenShadeInterpolator;
+ @Mock private AvalancheController mAvalancheController;
@Before
public void setUp() throws Exception {
@@ -153,7 +155,8 @@
mNotificationSectionsManager,
mBypassController,
mStatusBarKeyguardViewManager,
- mLargeScreenShadeInterpolator
+ mLargeScreenShadeInterpolator,
+ mAvalancheController
));
// Register the debug flags we use
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt
index 2c2b183..82725d6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt
@@ -25,6 +25,7 @@
import com.android.systemui.statusbar.notification.row.ExpandableView
import com.android.systemui.statusbar.notification.shared.NotificationsImprovedHunAnimation
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
+import com.android.systemui.statusbar.policy.AvalancheController
import com.android.systemui.util.mockito.mock
import com.google.common.truth.Expect
import com.google.common.truth.Truth.assertThat
@@ -48,6 +49,7 @@
@JvmField @Rule var expect: Expect = Expect.create()
private val largeScreenShadeInterpolator = mock<LargeScreenShadeInterpolator>()
+ private val avalancheController = mock<AvalancheController>()
private val hostView = FrameLayout(context)
private val stackScrollAlgorithm = StackScrollAlgorithm(context, hostView)
@@ -71,6 +73,7 @@
/* bypassController */ { false },
mStatusBarKeyguardViewManager,
largeScreenShadeInterpolator,
+ avalancheController
)
private val testableResources = mContext.getOrCreateTestableResources()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
index 041e61c..f666d8e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
@@ -27,6 +27,8 @@
import static com.google.common.truth.Truth.assertThat;
+import static kotlinx.coroutines.flow.FlowKt.flowOf;
+
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -44,8 +46,6 @@
import static java.util.Collections.emptySet;
-import static kotlinx.coroutines.flow.FlowKt.flowOf;
-
import android.app.ActivityManager;
import android.app.IWallpaperManager;
import android.app.WallpaperManager;
@@ -195,6 +195,8 @@
import dagger.Lazy;
+import kotlinx.coroutines.test.TestScope;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -208,8 +210,6 @@
import javax.inject.Provider;
-import kotlinx.coroutines.test.TestScope;
-
@SmallTest
@RunWith(AndroidTestingRunner.class)
@RunWithLooper(setAsMainLooper = true)
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 a6a4f24..8e9840a 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
@@ -59,8 +59,8 @@
import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository;
import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository;
import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor;
-import com.android.systemui.flags.FakeFeatureFlagsClassic;
-import com.android.systemui.flags.Flags;
+import com.android.systemui.flags.DisableSceneContainer;
+import com.android.systemui.flags.EnableSceneContainer;
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository;
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
@@ -76,6 +76,8 @@
import com.android.systemui.statusbar.data.repository.FakeKeyguardStatusBarRepository;
import com.android.systemui.statusbar.domain.interactor.KeyguardStatusBarInteractor;
import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
+import com.android.systemui.statusbar.phone.ui.StatusBarIconController;
+import com.android.systemui.statusbar.phone.ui.TintedIconManager;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
@@ -87,6 +89,8 @@
import com.android.systemui.util.settings.SecureSettings;
import com.android.systemui.util.time.FakeSystemClock;
+import kotlinx.coroutines.test.TestScope;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -95,13 +99,10 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import kotlinx.coroutines.test.TestScope;
-
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
public class KeyguardStatusBarViewControllerTest extends SysuiTestCase {
- private final FakeFeatureFlagsClassic mFeatureFlags = new FakeFeatureFlagsClassic();
@Mock
private CarrierTextController mCarrierTextController;
@Mock
@@ -115,9 +116,9 @@
@Mock
private StatusBarIconController mStatusBarIconController;
@Mock
- private StatusBarIconController.TintedIconManager.Factory mIconManagerFactory;
+ private TintedIconManager.Factory mIconManagerFactory;
@Mock
- private StatusBarIconController.TintedIconManager mIconManager;
+ private TintedIconManager mIconManager;
@Mock
private BatteryMeterViewController mBatteryMeterViewController;
@Mock
@@ -160,7 +161,6 @@
@Before
public void setup() throws Exception {
- mFeatureFlags.set(Flags.MIGRATE_KEYGUARD_STATUS_BAR_VIEW, false);
mShadeViewStateProvider = new TestShadeViewStateProvider();
MockitoAnnotations.initMocks(this);
@@ -217,7 +217,6 @@
mBiometricUnlockController,
mStatusBarStateController,
mStatusBarContentInsetsProvider,
- mFeatureFlags,
mUserManager,
mStatusBarUserChipViewModel,
mSecureSettings,
@@ -334,8 +333,8 @@
}
@Test
+ @DisableSceneContainer
public void onViewReAttached_flagOff_iconManagerNotReRegistered() {
- mFeatureFlags.set(Flags.MIGRATE_KEYGUARD_STATUS_BAR_VIEW, false);
mController.onViewAttached();
mController.onViewDetached();
reset(mStatusBarIconController);
@@ -346,8 +345,8 @@
}
@Test
+ @EnableSceneContainer
public void onViewReAttached_flagOn_iconManagerReRegistered() {
- mFeatureFlags.set(Flags.MIGRATE_KEYGUARD_STATUS_BAR_VIEW, true);
mController.onViewAttached();
mController.onViewDetached();
reset(mStatusBarIconController);
@@ -383,9 +382,8 @@
}
@Test
+ @EnableSceneContainer
public void setBatteryListening_true_flagOn_callbackNotAdded() {
- mFeatureFlags.set(Flags.MIGRATE_KEYGUARD_STATUS_BAR_VIEW, true);
-
mController.setBatteryListening(true);
verify(mBatteryController, never()).addCallback(any());
@@ -563,8 +561,8 @@
}
@Test
+ @DisableSceneContainer
public void updateViewState_dozingTrue_flagOff_viewHidden() {
- mFeatureFlags.set(Flags.MIGRATE_KEYGUARD_STATUS_BAR_VIEW, false);
mController.init();
mController.onViewAttached();
updateStateToKeyguard();
@@ -576,8 +574,8 @@
}
@Test
+ @DisableSceneContainer
public void updateViewState_dozingFalse_flagOff_viewShown() {
- mFeatureFlags.set(Flags.MIGRATE_KEYGUARD_STATUS_BAR_VIEW, false);
mController.init();
mController.onViewAttached();
updateStateToKeyguard();
@@ -589,8 +587,8 @@
}
@Test
+ @EnableSceneContainer
public void updateViewState_flagOn_doesNothing() {
- mFeatureFlags.set(Flags.MIGRATE_KEYGUARD_STATUS_BAR_VIEW, true);
mController.init();
mController.onViewAttached();
updateStateToKeyguard();
@@ -605,8 +603,8 @@
}
@Test
+ @EnableSceneContainer
public void updateViewStateWithAlphaAndVis_flagOn_doesNothing() {
- mFeatureFlags.set(Flags.MIGRATE_KEYGUARD_STATUS_BAR_VIEW, true);
mController.init();
mController.onViewAttached();
updateStateToKeyguard();
@@ -621,8 +619,8 @@
}
@Test
+ @EnableSceneContainer
public void setAlpha_flagOn_doesNothing() {
- mFeatureFlags.set(Flags.MIGRATE_KEYGUARD_STATUS_BAR_VIEW, true);
mController.init();
mController.onViewAttached();
updateStateToKeyguard();
@@ -635,8 +633,8 @@
}
@Test
+ @EnableSceneContainer
public void setDozing_flagOn_doesNothing() {
- mFeatureFlags.set(Flags.MIGRATE_KEYGUARD_STATUS_BAR_VIEW, true);
mController.init();
mController.onViewAttached();
updateStateToKeyguard();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewTest.java
index e88fd95..c44f979 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewTest.java
@@ -25,8 +25,8 @@
import androidx.test.filters.SmallTest;
-import com.android.systemui.res.R;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.res.R;
import org.junit.Before;
import org.junit.Test;
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 f6419a9..7271a5e 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
@@ -55,6 +55,8 @@
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.util.kotlin.JavaAdapter;
+import kotlinx.coroutines.test.TestScope;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -64,8 +66,6 @@
import java.util.Arrays;
import java.util.List;
-import kotlinx.coroutines.test.TestScope;
-
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationTapHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationTapHelperTest.java
index d25a06b..ccd1a8c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationTapHelperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationTapHelperTest.java
@@ -29,9 +29,9 @@
import androidx.test.filters.SmallTest;
-import com.android.systemui.res.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.classifier.FalsingManagerFake;
+import com.android.systemui.res.R;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.time.FakeSystemClock;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicyTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicyTest.kt
index 7deee5a..8d2c158 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicyTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicyTest.kt
@@ -36,6 +36,7 @@
import com.android.systemui.screenrecord.RecordingController
import com.android.systemui.settings.UserTracker
import com.android.systemui.statusbar.CommandQueue
+import com.android.systemui.statusbar.phone.ui.StatusBarIconController
import com.android.systemui.statusbar.policy.BluetoothController
import com.android.systemui.statusbar.policy.CastController
import com.android.systemui.statusbar.policy.DataSaverController
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index f947640..1000329 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -24,6 +24,8 @@
import static com.google.common.truth.Truth.assertThat;
+import static kotlinx.coroutines.flow.FlowKt.emptyFlow;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.mockito.ArgumentMatchers.any;
@@ -41,8 +43,6 @@
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
-import static kotlinx.coroutines.flow.FlowKt.emptyFlow;
-
import android.animation.Animator;
import android.app.AlarmManager;
import android.content.Context;
@@ -89,6 +89,8 @@
import com.google.common.truth.Expect;
+import kotlinx.coroutines.test.TestScope;
+
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
@@ -105,8 +107,6 @@
import java.util.HashSet;
import java.util.Map;
-import kotlinx.coroutines.test.TestScope;
-
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
@SmallTest
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
index f04a5ab..e38e31d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
@@ -19,6 +19,8 @@
import static com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants.EXPANSION_HIDDEN;
import static com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants.EXPANSION_VISIBLE;
+import static kotlinx.coroutines.test.TestCoroutineDispatchersKt.StandardTestDispatcher;
+
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
@@ -35,8 +37,6 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import static kotlinx.coroutines.test.TestCoroutineDispatchersKt.StandardTestDispatcher;
-
import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
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 9c3d9c6..66211c9 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
@@ -61,10 +61,11 @@
import com.android.systemui.statusbar.phone.HeadsUpAppearanceController;
import com.android.systemui.statusbar.phone.NotificationIconAreaController;
import com.android.systemui.statusbar.phone.StatusBarHideIconsForBouncerManager;
-import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.statusbar.phone.StatusBarLocationPublisher;
import com.android.systemui.statusbar.phone.fragment.dagger.StatusBarFragmentComponent;
import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController;
+import com.android.systemui.statusbar.phone.ui.DarkIconManager;
+import com.android.systemui.statusbar.phone.ui.StatusBarIconController;
import com.android.systemui.statusbar.pipeline.shared.ui.viewmodel.FakeCollapsedStatusBarViewBinder;
import com.android.systemui.statusbar.pipeline.shared.ui.viewmodel.FakeCollapsedStatusBarViewModel;
import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -117,9 +118,9 @@
@Mock
private PanelExpansionInteractor mPanelExpansionInteractor;
@Mock
- private StatusBarIconController.DarkIconManager.Factory mIconManagerFactory;
+ private DarkIconManager.Factory mIconManagerFactory;
@Mock
- private StatusBarIconController.DarkIconManager mIconManager;
+ private DarkIconManager mIconManager;
private FakeCollapsedStatusBarViewModel mCollapsedStatusBarViewModel;
private FakeCollapsedStatusBarViewBinder mCollapsedStatusBarViewBinder;
@Mock
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ui/StatusBarIconControllerImplTest.kt
similarity index 97%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImplTest.kt
rename to packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ui/StatusBarIconControllerImplTest.kt
index f6a8243..617c553 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ui/StatusBarIconControllerImplTest.kt
@@ -14,15 +14,16 @@
* limitations under the License.
*/
-package com.android.systemui.statusbar.phone
+package com.android.systemui.statusbar.phone.ui
import android.os.UserHandle
import androidx.test.filters.SmallTest
import com.android.internal.statusbar.StatusBarIcon
import com.android.systemui.SysuiTestCase
import com.android.systemui.statusbar.CommandQueue
-import com.android.systemui.statusbar.phone.StatusBarIconController.TAG_PRIMARY
-import com.android.systemui.statusbar.phone.StatusBarIconControllerImpl.EXTERNAL_SLOT_SUFFIX
+import com.android.systemui.statusbar.phone.StatusBarIconHolder
+import com.android.systemui.statusbar.phone.ui.StatusBarIconController.TAG_PRIMARY
+import com.android.systemui.statusbar.phone.ui.StatusBarIconControllerImpl.EXTERNAL_SLOT_SUFFIX
import com.android.systemui.statusbar.pipeline.icons.shared.BindableIconsRegistry
import com.android.systemui.statusbar.pipeline.icons.shared.model.BindableIcon
import com.android.systemui.statusbar.pipeline.icons.shared.model.ModernStatusBarViewCreator
@@ -42,7 +43,7 @@
private lateinit var iconList: StatusBarIconList
private lateinit var commandQueueCallbacks: CommandQueue.Callbacks
- private val iconGroup: StatusBarIconController.IconManager = mock()
+ private val iconGroup: IconManager = mock()
@Mock private lateinit var commandQueue: CommandQueue
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ui/StatusBarIconControllerTest.java
similarity index 84%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconControllerTest.java
rename to packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ui/StatusBarIconControllerTest.java
index ca31623..14bce9c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ui/StatusBarIconControllerTest.java
@@ -1,20 +1,20 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
+ * 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.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-package com.android.systemui.statusbar.phone;
-
-import static com.android.systemui.statusbar.phone.StatusBarIconHolder.TYPE_ICON;
+package com.android.systemui.statusbar.phone.ui;
import static junit.framework.Assert.assertTrue;
@@ -40,8 +40,8 @@
import com.android.systemui.statusbar.StatusBarIconView;
import com.android.systemui.statusbar.StatusIconDisplayable;
import com.android.systemui.statusbar.connectivity.ui.MobileContextProvider;
-import com.android.systemui.statusbar.phone.StatusBarIconController.DarkIconManager;
-import com.android.systemui.statusbar.phone.StatusBarIconController.IconManager;
+import com.android.systemui.statusbar.phone.StatusBarIconHolder;
+import com.android.systemui.statusbar.phone.StatusBarLocation;
import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags;
import com.android.systemui.statusbar.pipeline.icons.shared.BindableIconsRegistry;
import com.android.systemui.statusbar.pipeline.mobile.ui.MobileUiAdapter;
@@ -60,9 +60,9 @@
@SmallTest
public class StatusBarIconControllerTest extends LeakCheckedTest {
- private MobileContextProvider mMobileContextProvider = mock(MobileContextProvider.class);
- private MobileUiAdapter mMobileUiAdapter = mock(MobileUiAdapter.class);
- private MobileIconsViewModel mMobileIconsViewModel = mock(MobileIconsViewModel.class);
+ private final MobileContextProvider mMobileContextProvider = mock(MobileContextProvider.class);
+ private final MobileUiAdapter mMobileUiAdapter = mock(MobileUiAdapter.class);
+ private final MobileIconsViewModel mMobileIconsViewModel = mock(MobileIconsViewModel.class);
@Before
public void setup() {
@@ -123,22 +123,13 @@
}
private <T extends IconManager & TestableIconManager> void testCallOnAdd_forManager(T manager) {
- StatusBarIconHolder holder = holderForType(TYPE_ICON);
+ StatusBarIconHolder holder = StatusBarIconHolder.fromIcon(mock(StatusBarIcon.class));
manager.onIconAdded(0, "test_slot", false, holder);
assertTrue("Expected StatusBarIconView",
(manager.getViewAt(0) instanceof StatusBarIconView));
}
- private StatusBarIconHolder holderForType(int type) {
- switch (type) {
-
- case TYPE_ICON:
- default:
- return StatusBarIconHolder.fromIcon(mock(StatusBarIcon.class));
- }
- }
-
private static class TestDarkIconManager extends DarkIconManager
implements TestableIconManager {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconListTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ui/StatusBarIconListTest.java
similarity index 94%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconListTest.java
rename to packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ui/StatusBarIconListTest.java
index f0a4f3f..02a6301 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconListTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ui/StatusBarIconListTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2022 The Android Open Source Project
+ * Copyright (C) 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package com.android.systemui.statusbar.phone;
+package com.android.systemui.statusbar.phone.ui;
-import static com.android.systemui.statusbar.phone.StatusBarIconController.TAG_PRIMARY;
+import static com.android.systemui.statusbar.phone.ui.StatusBarIconController.TAG_PRIMARY;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNull;
@@ -29,7 +29,9 @@
import androidx.test.runner.AndroidJUnit4;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.statusbar.phone.StatusBarIconList.Slot;
+import com.android.systemui.statusbar.phone.StatusBarIconHolder;
+import com.android.systemui.statusbar.phone.ui.StatusBarIconList;
+import com.android.systemui.statusbar.phone.ui.StatusBarIconList.Slot;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HotspotControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HotspotControllerImplTest.java
index 3fae3f6..784fb71 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HotspotControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HotspotControllerImplTest.java
@@ -38,9 +38,9 @@
import androidx.test.filters.SmallTest;
-import com.android.systemui.res.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.res.R;
import com.android.systemui.settings.UserTracker;
import org.junit.Before;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/InflatedSmartRepliesTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/InflatedSmartRepliesTest.java
index bf280c9..456723d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/InflatedSmartRepliesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/InflatedSmartRepliesTest.java
@@ -37,8 +37,8 @@
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
-import com.android.systemui.res.R;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.res.R;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.DevicePolicyManagerWrapper;
import com.android.systemui.shared.system.PackageManagerWrapper;
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 479309c..3a086ae 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
@@ -52,7 +52,6 @@
import java.util.Random;
-
@SmallTest
@TestableLooper.RunWithLooper
@RunWith(AndroidTestingRunner.class)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyConstantsTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyConstantsTest.java
index b9557d2..a9681e0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyConstantsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyConstantsTest.java
@@ -21,7 +21,6 @@
import static junit.framework.Assert.assertTrue;
import android.app.RemoteInput;
-import android.os.Handler;
import android.provider.DeviceConfig;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java
index 4b6c68a..a213c85 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java
@@ -47,11 +47,11 @@
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.systemui.res.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.res.R;
import com.android.systemui.shade.ShadeController;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.SmartReplyController;
@@ -60,6 +60,9 @@
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
import com.android.systemui.statusbar.phone.KeyguardDismissUtil;
+import kotlin.sequences.Sequence;
+import kotlin.sequences.SequencesKt;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -76,9 +79,6 @@
import java.util.stream.IntStream;
import java.util.stream.Stream;
-import kotlin.sequences.Sequence;
-import kotlin.sequences.SequencesKt;
-
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@SmallTest
diff --git a/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/gloweffect/GlowPieEffectTest.kt b/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/gloweffect/GlowPieEffectTest.kt
deleted file mode 100644
index 8105cc5..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/gloweffect/GlowPieEffectTest.kt
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.surfaceeffects.gloweffect
-
-import android.graphics.Color
-import android.graphics.RenderEffect
-import android.testing.AndroidTestingRunner
-import android.testing.TestableLooper
-import androidx.test.filters.SmallTest
-import com.android.systemui.animation.AnimatorTestRule
-import com.android.systemui.model.SysUiStateTest
-import com.android.systemui.surfaceeffects.RenderEffectDrawCallback
-import com.google.common.truth.Truth.assertThat
-import org.junit.Rule
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@SmallTest
-@RunWith(AndroidTestingRunner::class)
-@TestableLooper.RunWithLooper(setAsMainLooper = true)
-class GlowPieEffectTest : SysUiStateTest() {
-
- @get:Rule val animatorTestRule = AnimatorTestRule(this)
-
- @Test
- fun play_triggersDrawCallback() {
- var effectFromCallback: RenderEffect? = null
- val glowPieEffectConfig =
- GlowPieEffectConfig(
- centerX = 0f,
- centerY = 0f,
- width = 1f,
- height = 1f,
- cornerRadius = 0.5f,
- colors = intArrayOf(Color.RED, Color.GREEN, Color.BLUE)
- )
- val drawCallback =
- object : RenderEffectDrawCallback {
- override fun onDraw(renderEffect: RenderEffect) {
- effectFromCallback = renderEffect
- }
- }
- val glowPieEffect = GlowPieEffect(glowPieEffectConfig, drawCallback)
-
- assertThat(effectFromCallback).isNull()
-
- glowPieEffect.play()
-
- animatorTestRule.advanceTimeBy(100L)
-
- assertThat(effectFromCallback).isNotNull()
- }
-
- @Test
- fun finish_cancelsAnimator() {
- val glowPieEffectConfig =
- GlowPieEffectConfig(
- centerX = 0f,
- centerY = 0f,
- width = 1f,
- height = 1f,
- cornerRadius = 0.5f,
- colors = intArrayOf(Color.RED, Color.GREEN, Color.BLUE)
- )
- val drawCallback =
- object : RenderEffectDrawCallback {
- override fun onDraw(renderEffect: RenderEffect) {}
- }
- val glowPieEffect = GlowPieEffect(glowPieEffectConfig, drawCallback)
-
- glowPieEffect.play()
- animatorTestRule.advanceTimeBy(100L)
-
- assertThat(glowPieEffect.mainAnimator.isRunning).isTrue()
-
- glowPieEffect.finish()
-
- assertThat(glowPieEffect.mainAnimator.isRunning).isFalse()
- }
-
- @Test
- fun glowPie_progress_computesProgressCorrectly() {
- val myGlowPieConfig =
- object : GlowPieEffect.GlowPie {
- override val startMs: Float = 0f
- override val endMs: Float = GlowPieEffect.DURATION_MS.toFloat()
- override val startAngle: Float = 0f
- override val endAngle: Float = 6f * GlowPieEffect.PI
- override val alphaFadeStartMs: Float = 0f
- override val alphaFadeEndMs: Float = GlowPieEffect.DURATION_MS.toFloat()
- override var progress: Float = 0f
- override var time: Float = 0f
- }
-
- val playTime = GlowPieEffect.DURATION_MS.toFloat() * 0.5f
- val tolerance = 1e-4f
- myGlowPieConfig.updateProgress(playTime)
-
- assertThat(myGlowPieConfig.time).isWithin(tolerance).of(playTime)
- assertThat(myGlowPieConfig.progress).isWithin(tolerance).of(0.5f)
- assertThat(myGlowPieConfig.angle()).isWithin(tolerance).of(-3.5f * GlowPieEffect.PI)
- assertThat(myGlowPieConfig.bottomThreshold())
- .isWithin(tolerance)
- .of((1f - GlowPieEffect.FEATHER) * 0.5f)
- assertThat(myGlowPieConfig.topThreshold())
- .isWithin(tolerance)
- .of((1f + GlowPieEffect.FEATHER) * 0.5f)
- assertThat(myGlowPieConfig.alpha()).isWithin(tolerance).of(0.5f)
-
- myGlowPieConfig.resetProgress()
-
- assertThat(myGlowPieConfig.time).isEqualTo(0f)
- assertThat(myGlowPieConfig.progress).isEqualTo(0f)
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/FakeExecutorTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/FakeExecutorTest.java
index 31bad2c..9dfa14d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/FakeExecutorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/FakeExecutorTest.java
@@ -29,6 +29,8 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.util.time.FakeSystemClock;
+import kotlin.jvm.functions.Function4;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -36,8 +38,6 @@
import java.util.ArrayList;
import java.util.List;
-import kotlin.jvm.functions.Function4;
-
@SmallTest
@RunWith(AndroidTestingRunner.class)
public class FakeExecutorTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wallpapers/data/repository/WallpaperRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/wallpapers/data/repository/WallpaperRepositoryImplTest.kt
index f8b096a..7d89a55 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wallpapers/data/repository/WallpaperRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/wallpapers/data/repository/WallpaperRepositoryImplTest.kt
@@ -33,6 +33,7 @@
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
@@ -41,13 +42,15 @@
@OptIn(ExperimentalCoroutinesApi::class)
class WallpaperRepositoryImplTest : SysuiTestCase() {
- private val testScope = TestScope(StandardTestDispatcher())
+ private val testDispatcher = StandardTestDispatcher()
+ private val testScope = TestScope(testDispatcher)
private val userRepository = FakeUserRepository()
private val wallpaperManager: WallpaperManager = mock()
private val underTest: WallpaperRepositoryImpl by lazy {
WallpaperRepositoryImpl(
testScope.backgroundScope,
+ testDispatcher,
fakeBroadcastDispatcher,
userRepository,
wallpaperManager,
@@ -102,8 +105,10 @@
userRepository.setUserInfos(listOf(USER_WITH_SUPPORTED_WP))
userRepository.setSelectedUserInfo(USER_WITH_SUPPORTED_WP)
- // WHEN the repo initially starts up (underTest is lazy), then it fetches the current
- // value for the wallpaper
+ // Start up the repo and let it run the initial fetch
+ underTest.wallpaperInfo
+ runCurrent()
+
assertThat(underTest.wallpaperInfo.value).isEqualTo(SUPPORTED_WP)
}
@@ -282,6 +287,10 @@
userRepository.setUserInfos(listOf(USER_WITH_SUPPORTED_WP))
userRepository.setSelectedUserInfo(USER_WITH_SUPPORTED_WP)
+ // Start up the repo and let it run the initial fetch
+ underTest.wallpaperSupportsAmbientMode
+ runCurrent()
+
// WHEN the repo initially starts up (underTest is lazy), then it fetches the current
// value for the wallpaper
assertThat(underTest.wallpaperSupportsAmbientMode.value).isTrue()
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 d9a0c4b..db998f3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
@@ -30,6 +30,8 @@
import static com.google.common.truth.Truth.assertThat;
+import static kotlinx.coroutines.flow.StateFlowKt.MutableStateFlow;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
@@ -50,8 +52,6 @@
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
-import static kotlinx.coroutines.flow.StateFlowKt.MutableStateFlow;
-
import android.app.ActivityManager;
import android.app.IActivityManager;
import android.app.INotificationManager;
@@ -207,6 +207,8 @@
import com.android.wm.shell.taskview.TaskViewTransitions;
import com.android.wm.shell.transition.Transitions;
+import kotlinx.coroutines.test.TestScope;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -225,8 +227,6 @@
import java.util.Optional;
import java.util.concurrent.Executor;
-import kotlinx.coroutines.test.TestScope;
-
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
diff --git a/packages/SystemUI/tests/utils/src/android/view/LayoutInflaterKosmos.kt b/packages/SystemUI/tests/utils/src/android/view/LayoutInflaterKosmos.kt
index 34c0a79..21dea6b 100644
--- a/packages/SystemUI/tests/utils/src/android/view/LayoutInflaterKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/android/view/LayoutInflaterKosmos.kt
@@ -19,5 +19,5 @@
import android.content.applicationContext
import com.android.systemui.kosmos.Kosmos
-val Kosmos.layoutInflater: LayoutInflater by
+var Kosmos.layoutInflater: LayoutInflater by
Kosmos.Fixture { LayoutInflater.from(applicationContext) }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/FpsUnlockTrackerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/FpsUnlockTrackerKosmos.kt
new file mode 100644
index 0000000..6085a1f
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/FpsUnlockTrackerKosmos.kt
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.biometrics
+
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.util.mockito.mock
+
+val Kosmos.fpsUnlockTracker by Kosmos.Fixture { mock<FpsUnlockTracker>() }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinderKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinderKosmos.kt
new file mode 100644
index 0000000..8281984
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinderKosmos.kt
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.biometrics.ui.binder
+
+import android.content.applicationContext
+import android.view.layoutInflater
+import android.view.windowManager
+import com.android.systemui.biometrics.domain.interactor.biometricStatusInteractor
+import com.android.systemui.biometrics.domain.interactor.displayStateInteractor
+import com.android.systemui.biometrics.domain.interactor.sideFpsSensorInteractor
+import com.android.systemui.biometrics.fpsUnlockTracker
+import com.android.systemui.keyguard.domain.interactor.deviceEntrySideFpsOverlayInteractor
+import com.android.systemui.keyguard.ui.viewmodel.sideFpsProgressBarViewModel
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.kosmos.applicationCoroutineScope
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+
+@OptIn(ExperimentalCoroutinesApi::class)
+val Kosmos.sideFpsOverlayViewBinder by Fixture {
+ SideFpsOverlayViewBinder(
+ applicationScope = applicationCoroutineScope,
+ applicationContext = applicationContext,
+ { biometricStatusInteractor },
+ { displayStateInteractor },
+ { deviceEntrySideFpsOverlayInteractor },
+ { fpsUnlockTracker },
+ { layoutInflater },
+ { sideFpsProgressBarViewModel },
+ { sideFpsSensorInteractor },
+ { windowManager }
+ )
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModelKosmos.kt
new file mode 100644
index 0000000..de03855
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModelKosmos.kt
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.biometrics.ui.viewmodel
+
+import android.content.applicationContext
+import com.android.systemui.biometrics.domain.interactor.displayStateInteractor
+import com.android.systemui.biometrics.domain.interactor.sideFpsSensorInteractor
+import com.android.systemui.keyguard.domain.interactor.deviceEntrySideFpsOverlayInteractor
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+
+@OptIn(ExperimentalCoroutinesApi::class)
+val Kosmos.sideFpsOverlayViewModel by Fixture {
+ SideFpsOverlayViewModel(
+ applicationContext = applicationContext,
+ deviceEntrySideFpsOverlayInteractor = deviceEntrySideFpsOverlayInteractor,
+ displayStateInteractor = displayStateInteractor,
+ sfpsSensorInteractor = sideFpsSensorInteractor,
+ )
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorKosmos.kt
index 4a02f6d..4394847 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorKosmos.kt
@@ -26,7 +26,7 @@
import com.android.systemui.kosmos.testScope
import com.android.systemui.log.sessionTracker
import com.android.systemui.power.domain.interactor.powerInteractor
-import com.android.systemui.scene.domain.interactor.sceneInteractor
+import com.android.systemui.scene.domain.interactor.sceneBackInteractor
val Kosmos.bouncerInteractor by Fixture {
BouncerInteractor(
@@ -38,6 +38,6 @@
powerInteractor = powerInteractor,
uiEventLogger = uiEventLogger,
sessionTracker = sessionTracker,
- sceneInteractor = sceneInteractor,
+ sceneBackInteractor = sceneBackInteractor,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractorKosmos.kt
new file mode 100644
index 0000000..4ccee6f
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractorKosmos.kt
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyguard.domain.interactor
+
+import android.content.applicationContext
+import com.android.keyguard.keyguardUpdateMonitor
+import com.android.systemui.bouncer.domain.interactor.alternateBouncerInteractor
+import com.android.systemui.bouncer.domain.interactor.primaryBouncerInteractor
+import com.android.systemui.keyguard.data.repository.deviceEntryFingerprintAuthRepository
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.scene.domain.interactor.sceneInteractor
+
+val Kosmos.deviceEntrySideFpsOverlayInteractor: DeviceEntrySideFpsOverlayInteractor by
+ Kosmos.Fixture {
+ DeviceEntrySideFpsOverlayInteractor(
+ applicationScope = testScope.backgroundScope,
+ context = applicationContext,
+ deviceEntryFingerprintAuthRepository = deviceEntryFingerprintAuthRepository,
+ sceneInteractor = sceneInteractor,
+ primaryBouncerInteractor = primaryBouncerInteractor,
+ alternateBouncerInteractor = alternateBouncerInteractor,
+ keyguardUpdateMonitor = keyguardUpdateMonitor
+ )
+ }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/SideFpsProgressBarViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/SideFpsProgressBarViewModelKosmos.kt
new file mode 100644
index 0000000..8da16fc
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/SideFpsProgressBarViewModelKosmos.kt
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+@file:OptIn(ExperimentalCoroutinesApi::class)
+
+package com.android.systemui.keyguard.ui.viewmodel
+
+import android.content.applicationContext
+import com.android.systemui.biometrics.domain.interactor.biometricStatusInteractor
+import com.android.systemui.biometrics.domain.interactor.displayStateInteractor
+import com.android.systemui.biometrics.domain.interactor.sideFpsSensorInteractor
+import com.android.systemui.deviceentry.domain.interactor.deviceEntryFingerprintAuthInteractor
+import com.android.systemui.keyguard.domain.interactor.keyguardInteractor
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.testDispatcher
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.power.domain.interactor.powerInteractor
+import com.android.systemui.statusbar.phone.dozeServiceHost
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+
+val Kosmos.sideFpsProgressBarViewModel by
+ Kosmos.Fixture {
+ SideFpsProgressBarViewModel(
+ context = applicationContext,
+ biometricStatusInteractor = biometricStatusInteractor,
+ deviceEntryFingerprintAuthInteractor = deviceEntryFingerprintAuthInteractor,
+ sfpsSensorInteractor = sideFpsSensorInteractor,
+ dozeServiceHost = dozeServiceHost,
+ keyguardInteractor = keyguardInteractor,
+ displayStateInteractor = displayStateInteractor,
+ mainDispatcher = testDispatcher,
+ applicationScope = testScope.backgroundScope,
+ powerInteractor = powerInteractor
+ )
+ }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneKosmos.kt
index 7f6a7bd..16d08dd 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneKosmos.kt
@@ -32,4 +32,15 @@
val Kosmos.scenes by Fixture { fakeScenes }
val Kosmos.initialSceneKey by Fixture { Scenes.Lockscreen }
-val Kosmos.sceneContainerConfig by Fixture { SceneContainerConfig(sceneKeys, initialSceneKey) }
+val Kosmos.sceneContainerConfig by Fixture {
+ val navigationDistances =
+ mapOf(
+ Scenes.Gone to 0,
+ Scenes.Lockscreen to 0,
+ Scenes.Communal to 1,
+ Scenes.Shade to 2,
+ Scenes.QuickSettings to 3,
+ Scenes.Bouncer to 4,
+ )
+ SceneContainerConfig(sceneKeys, initialSceneKey, navigationDistances)
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/interactor/SceneBackInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/interactor/SceneBackInteractorKosmos.kt
new file mode 100644
index 0000000..e46ede6
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/interactor/SceneBackInteractorKosmos.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.scene.domain.interactor
+
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.scene.sceneContainerConfig
+import com.android.systemui.scene.shared.logger.sceneLogger
+
+val Kosmos.sceneBackInteractor by Fixture {
+ SceneBackInteractor(
+ logger = sceneLogger,
+ sceneContainerConfig = sceneContainerConfig,
+ )
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/interactor/SceneContainerStartableKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/interactor/SceneContainerStartableKosmos.kt
index c7cf934..c0f5039 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/interactor/SceneContainerStartableKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/interactor/SceneContainerStartableKosmos.kt
@@ -39,7 +39,6 @@
import com.android.systemui.statusbar.notificationShadeWindowController
import com.android.systemui.statusbar.phone.centralSurfaces
import com.android.systemui.statusbar.policy.domain.interactor.deviceProvisioningInteractor
-import dagger.Lazy
val Kosmos.sceneContainerStartable by Fixture {
SceneContainerStartable(
@@ -55,8 +54,8 @@
falsingCollector = falsingCollector,
falsingManager = falsingManager,
powerInteractor = powerInteractor,
- simBouncerInteractor = Lazy { simBouncerInteractor },
- authenticationInteractor = Lazy { authenticationInteractor },
+ simBouncerInteractor = { simBouncerInteractor },
+ authenticationInteractor = { authenticationInteractor },
windowController = notificationShadeWindowController,
deviceProvisioningInteractor = deviceProvisioningInteractor,
centralSurfaces = centralSurfaces,
@@ -65,5 +64,6 @@
faceUnlockInteractor = deviceEntryFaceAuthInteractor,
shadeInteractor = shadeInteractor,
uiEventLogger = uiEventLogger,
+ sceneBackInteractor = sceneBackInteractor,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/screenshot/scroll/FakeSession.java b/packages/SystemUI/tests/utils/src/com/android/systemui/screenshot/scroll/FakeSession.java
index 3b7b158..502e0de 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/screenshot/scroll/FakeSession.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/screenshot/scroll/FakeSession.java
@@ -32,8 +32,6 @@
import android.media.Image;
import android.util.Log;
-import com.android.systemui.screenshot.scroll.ScrollCaptureClient;
-
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/collection/NotificationEntryBuilder.java b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/collection/NotificationEntryBuilder.java
index b91f7e6..2bd584e 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/collection/NotificationEntryBuilder.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/collection/NotificationEntryBuilder.java
@@ -33,10 +33,10 @@
import com.android.systemui.statusbar.notification.collection.listbuilder.NotifSection;
import com.android.systemui.util.time.FakeSystemClock;
-import java.util.ArrayList;
-
import kotlin.Unit;
+import java.util.ArrayList;
+
/**
* Combined builder for constructing a NotificationEntry and its associated StatusBarNotification
* and Ranking. Is largely a proxy for the SBN and Ranking builders, but does a little extra magic
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/AmbientStateKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/AmbientStateKosmos.kt
index 7f6f698..383e31d 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/AmbientStateKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/AmbientStateKosmos.kt
@@ -33,5 +33,6 @@
/*bypassController=*/ stackScrollAlgorithmBypassController,
/*statusBarKeyguardViewManager=*/ statusBarKeyguardViewManager,
/*largeScreenShadeInterpolator=*/ largeScreenShadeInterpolator,
+ /*avalancheController=*/ avalancheController,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmKosmos.kt
index 67343c95..e20ce27 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmKosmos.kt
@@ -18,6 +18,7 @@
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.statusbar.policy.AvalancheController
import com.android.systemui.util.mockito.mock
var Kosmos.stackScrollAlgorithmSectionProvider by Fixture {
@@ -27,3 +28,7 @@
var Kosmos.stackScrollAlgorithmBypassController by Fixture {
mock<StackScrollAlgorithm.BypassController>()
}
+
+var Kosmos.avalancheController by Fixture {
+ mock<AvalancheController>()
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeStatusBarIconController.java b/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeStatusBarIconController.java
index 3774d1d..a8328e4 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeStatusBarIconController.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeStatusBarIconController.java
@@ -17,9 +17,9 @@
import android.testing.LeakCheck;
import com.android.internal.statusbar.StatusBarIcon;
-import com.android.systemui.statusbar.phone.StatusBarIconController;
-import com.android.systemui.statusbar.phone.StatusBarIconController.IconManager;
import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.CallIndicatorIconState;
+import com.android.systemui.statusbar.phone.ui.IconManager;
+import com.android.systemui.statusbar.phone.ui.StatusBarIconController;
import java.util.List;
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/LeakCheckedTest.java b/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/LeakCheckedTest.java
index ec1f352..5d21ddd 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/LeakCheckedTest.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/LeakCheckedTest.java
@@ -21,7 +21,7 @@
import com.android.systemui.plugins.PluginManager;
import com.android.systemui.statusbar.connectivity.NetworkController;
import com.android.systemui.statusbar.phone.ManagedProfileController;
-import com.android.systemui.statusbar.phone.StatusBarIconController;
+import com.android.systemui.statusbar.phone.ui.StatusBarIconController;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.BluetoothController;
import com.android.systemui.statusbar.policy.CastController;
diff --git a/ravenwood/Android.bp b/ravenwood/Android.bp
index 8905ad3..3337419 100644
--- a/ravenwood/Android.bp
+++ b/ravenwood/Android.bp
@@ -163,6 +163,8 @@
test_suites: ["general-tests"],
data: [
":framework-minus-apex.ravenwood.stats",
+ ":framework-minus-apex.ravenwood.apis",
":services.core.ravenwood.stats",
+ ":services.core.ravenwood.apis",
],
}
diff --git a/ravenwood/scripts/ravenwood-stats-collector.sh b/ravenwood/scripts/ravenwood-stats-collector.sh
index 4dcaa2b..b5843d0 100755
--- a/ravenwood/scripts/ravenwood-stats-collector.sh
+++ b/ravenwood/scripts/ravenwood-stats-collector.sh
@@ -17,8 +17,9 @@
set -e
-# Output file
-out=/tmp/ravenwood-stats-all.csv
+# Output files
+stats=/tmp/ravenwood-stats-all.csv
+apis=/tmp/ravenwood-apis-all.csv
# Where the input files are.
path=$ANDROID_BUILD_TOP/out/host/linux-x86/testcases/ravenwood-stats-checker/x86_64/
@@ -41,12 +42,28 @@
sed -e '1d' -e "s/^/$jar,/" $file
}
-collect() {
- echo 'Jar,PackageName,ClassName,SupportedMethods,TotalMethods'
- dump "framework-minus-apex" hoststubgen_framework-minus-apex_stats.csv
- dump "service.core" hoststubgen_services.core_stats.csv
+collect_stats() {
+ local out="$1"
+ {
+ echo 'Jar,PackageName,ClassName,SupportedMethods,TotalMethods'
+ dump "framework-minus-apex" hoststubgen_framework-minus-apex_stats.csv
+ dump "service.core" hoststubgen_services.core_stats.csv
+ } > "$out"
+
+ echo "Stats CVS created at $out"
}
-collect >$out
+collect_apis() {
+ local out="$1"
+ {
+ echo 'Jar,PackageName,ClassName,MethodName,Descriptor'
+ dump "framework-minus-apex" hoststubgen_framework-minus-apex_apis.csv
+ dump "service.core" hoststubgen_services.core_apis.csv
+ } > "$out"
-echo "Full dump CVS created at $out"
+ echo "API CVS created at $out"
+}
+
+
+collect_stats $stats
+collect_apis $apis
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index e171064..2d1aba4 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -1132,20 +1132,17 @@
return;
}
- int phoneId = -1;
int subscriptionId = SubscriptionManager.DEFAULT_SUBSCRIPTION_ID;
- if(Flags.preventSystemServerAndPhoneDeadlock()) {
- // Legacy applications pass SubscriptionManager.DEFAULT_SUB_ID,
- // force all illegal subId to SubscriptionManager.DEFAULT_SUB_ID
- if (!SubscriptionManager.isValidSubscriptionId(subId)) {
- if (DBG) {
- log("invalid subscription id, use default id");
- }
- } else { //APP specify subID
- subscriptionId = subId;
+ // Legacy applications pass SubscriptionManager.DEFAULT_SUB_ID,
+ // force all illegal subId to SubscriptionManager.DEFAULT_SUB_ID
+ if (!SubscriptionManager.isValidSubscriptionId(subId)) {
+ if (DBG) {
+ log("invalid subscription id, use default id");
}
- phoneId = getPhoneIdFromSubId(subscriptionId);
+ } else { //APP specify subID
+ subscriptionId = subId;
}
+ int phoneId = getPhoneIdFromSubId(subscriptionId);
synchronized (mRecords) {
// register
@@ -1166,23 +1163,8 @@
r.renounceFineLocationAccess = renounceFineLocationAccess;
r.callerUid = Binder.getCallingUid();
r.callerPid = Binder.getCallingPid();
-
- if(!Flags.preventSystemServerAndPhoneDeadlock()) {
- // Legacy applications pass SubscriptionManager.DEFAULT_SUB_ID,
- // force all illegal subId to SubscriptionManager.DEFAULT_SUB_ID
- if (!SubscriptionManager.isValidSubscriptionId(subId)) {
- if (DBG) {
- log("invalid subscription id, use default id");
- }
- r.subId = SubscriptionManager.DEFAULT_SUBSCRIPTION_ID;
- } else {//APP specify subID
- r.subId = subId;
- }
- r.phoneId = getPhoneIdFromSubId(r.subId);
- } else {
- r.subId = subscriptionId;
- r.phoneId = phoneId;
- }
+ r.subId = subscriptionId;
+ r.phoneId = phoneId;
r.eventList = events;
if (DBG) {
@@ -1928,14 +1910,8 @@
}
private void notifyCarrierNetworkChangeWithPermission(int subId, boolean active) {
- int phoneId = -1;
- if(Flags.preventSystemServerAndPhoneDeadlock()) {
- phoneId = getPhoneIdFromSubId(subId);
- }
+ int phoneId = getPhoneIdFromSubId(subId);
synchronized (mRecords) {
- if(!Flags.preventSystemServerAndPhoneDeadlock()) {
- phoneId = getPhoneIdFromSubId(subId);
- }
mCarrierNetworkChangeState[phoneId] = active;
if (VDBG) {
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index eec22c9..96228b2 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -2425,7 +2425,7 @@
final long before24Hr = Math.max(0,
SystemClock.elapsedRealtime() - (24 * 60 * 60 * 1000));
final long lastTimeOutAt = fgsTypeInfo.getTimeLimitExceededAt();
- if (fgsTypeInfo.getFirstFgsStartTime() < before24Hr
+ if (fgsTypeInfo.getFirstFgsStartRealtime() < before24Hr
|| (lastTimeOutAt != Long.MIN_VALUE
&& r.app.mState.getLastTopTime() > lastTimeOutAt)) {
// Reset the time limit info for this fgs type if it has been
@@ -3724,6 +3724,33 @@
return fgsType;
}
+ /**
+ * @return the constant time limit defined for the given foreground service type.
+ */
+ private long getTimeLimitForFgsType(int foregroundServiceType) {
+ return switch (foregroundServiceType) {
+ case ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROCESSING ->
+ mAm.mConstants.mMediaProcessingFgsTimeoutDuration;
+ case ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC ->
+ mAm.mConstants.mDataSyncFgsTimeoutDuration;
+ // Add logic for time limits introduced in the future for other fgs types above.
+ default -> Long.MAX_VALUE;
+ };
+ }
+
+ /**
+ * @return the next stop time for the given type, based on how long it has already ran for.
+ * The total runtime is automatically reset 24hrs after the first fgs start of this type
+ * or if the app has recently been in the TOP state when the app calls startForeground().
+ */
+ private long getNextFgsStopTime(int fgsType, TimeLimitedFgsInfo fgsInfo) {
+ final long timeLimit = getTimeLimitForFgsType(fgsType);
+ if (timeLimit == Long.MAX_VALUE) {
+ return Long.MAX_VALUE;
+ }
+ return fgsInfo.getLastFgsStartTime() + Math.max(0, timeLimit - fgsInfo.getTotalRuntime());
+ }
+
private void maybeUpdateFgsTrackingLocked(ServiceRecord sr, int previousFgsType) {
final int previouslyTimeLimitedType = getTimeLimitedFgsType(previousFgsType);
if (previouslyTimeLimitedType == ServiceInfo.FOREGROUND_SERVICE_TYPE_NONE
@@ -3755,7 +3782,7 @@
}
traceInstant("FGS start: ", sr);
- final long nowRealtime = SystemClock.elapsedRealtime();
+ final long nowUptime = SystemClock.uptimeMillis();
// Fetch/create/update the fgs info for the time-limited type.
SparseArray<TimeLimitedFgsInfo> fgsInfo = mTimeLimitedFgsInfo.get(sr.appInfo.uid);
@@ -3766,10 +3793,10 @@
final int timeLimitedFgsType = getTimeLimitedFgsType(sr.foregroundServiceType);
TimeLimitedFgsInfo fgsTypeInfo = fgsInfo.get(timeLimitedFgsType);
if (fgsTypeInfo == null) {
- fgsTypeInfo = sr.createTimeLimitedFgsInfo(nowRealtime);
+ fgsTypeInfo = sr.createTimeLimitedFgsInfo(nowUptime);
fgsInfo.put(timeLimitedFgsType, fgsTypeInfo);
}
- fgsTypeInfo.setLastFgsStartTime(nowRealtime);
+ fgsTypeInfo.setLastFgsStartTime(nowUptime);
// We'll cancel the previous ANR timer and start a fresh one below.
mFGSAnrTimer.cancel(sr);
@@ -3777,7 +3804,7 @@
final Message msg = mAm.mHandler.obtainMessage(
ActivityManagerService.SERVICE_FGS_TIMEOUT_MSG, sr);
- final long timeoutCallbackTime = sr.getNextFgsStopTime(timeLimitedFgsType, fgsTypeInfo);
+ final long timeoutCallbackTime = getNextFgsStopTime(timeLimitedFgsType, fgsTypeInfo);
if (timeoutCallbackTime == Long.MAX_VALUE) {
// This should never happen since we only get to this point if the service record's
// foregroundServiceType attribute contains a type that can be timed-out.
@@ -3833,6 +3860,20 @@
mFGSAnrTimer.discard(sr);
return;
}
+
+ final long lastTopTime = sr.app.mState.getLastTopTime();
+ final long constantTimeLimit = getTimeLimitForFgsType(fgsType);
+ final long nowUptime = SystemClock.uptimeMillis();
+ if (constantTimeLimit > (nowUptime - lastTopTime)) {
+ // The app was in the TOP state after the FGS was started so its time allowance
+ // should be counted from that time since this is considered a user interaction
+ mFGSAnrTimer.discard(sr);
+ final Message msg = mAm.mHandler.obtainMessage(
+ ActivityManagerService.SERVICE_FGS_TIMEOUT_MSG, sr);
+ mAm.mHandler.sendMessageAtTime(msg, lastTopTime + constantTimeLimit);
+ return;
+ }
+
Slog.e(TAG_SERVICE, "FGS (" + ServiceInfo.foregroundServiceTypeToLabel(fgsType)
+ ") timed out: " + sr);
mFGSAnrTimer.accept(sr);
@@ -3843,14 +3884,13 @@
final TimeLimitedFgsInfo fgsTypeInfo = fgsInfo.get(fgsType);
if (fgsTypeInfo != null) {
// Update total runtime for the time-limited fgs type and mark it as timed out.
- final long nowRealtime = SystemClock.elapsedRealtime();
fgsTypeInfo.updateTotalRuntime();
- fgsTypeInfo.setTimeLimitExceededAt(nowRealtime);
+ fgsTypeInfo.setTimeLimitExceededAt(nowUptime);
logFGSStateChangeLocked(sr,
FOREGROUND_SERVICE_STATE_CHANGED__STATE__TIMED_OUT,
- nowRealtime > fgsTypeInfo.getLastFgsStartTime()
- ? (int) (nowRealtime - fgsTypeInfo.getLastFgsStartTime()) : 0,
+ nowUptime > fgsTypeInfo.getLastFgsStartTime()
+ ? (int) (nowUptime - fgsTypeInfo.getLastFgsStartTime()) : 0,
FGS_STOP_REASON_UNKNOWN,
FGS_TYPE_POLICY_CHECK_UNKNOWN,
FOREGROUND_SERVICE_STATE_CHANGED__FGS_START_API__FGSSTARTAPI_NA,
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index f7ed702..9e06b75 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -2473,6 +2473,9 @@
pw.print(" "); pw.print(KEY_PSS_TO_RSS_THRESHOLD_MODIFIER);
pw.print("="); pw.println(PSS_TO_RSS_THRESHOLD_MODIFIER);
+ pw.print(" "); pw.print(KEY_MAX_PREVIOUS_TIME);
+ pw.print("="); pw.println(MAX_PREVIOUS_TIME);
+
pw.println();
if (mOverrideMaxCachedProcesses >= 0) {
pw.print(" mOverrideMaxCachedProcesses="); pw.println(mOverrideMaxCachedProcesses);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index cf09cfb..49f2c8b 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -4436,8 +4436,17 @@
packageName, null, userId);
}
- final boolean clearPendingIntentsForStoppedApp = (android.content.pm.Flags.stayStopped()
- && packageStateStopped);
+ boolean clearPendingIntentsForStoppedApp = false;
+ try {
+ clearPendingIntentsForStoppedApp = (packageStateStopped
+ && android.content.pm.Flags.stayStopped());
+ } catch (IllegalStateException e) {
+ // It's unlikely for a package to be force-stopped early in the boot cycle. So, if we
+ // check for 'packageStateStopped' which should evaluate to 'false', then this should
+ // ensure we are not accessing the flag early in the boot cycle. As an additional
+ // safety measure, catch the exception and ignore to avoid causing a device restart.
+ clearPendingIntentsForStoppedApp = false;
+ }
if (packageName == null || uninstalling || clearPendingIntentsForStoppedApp) {
final int cancelReason;
if (packageName == null) {
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index 065f3bd..8eca4fc 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -33,6 +33,7 @@
import android.annotation.ElapsedRealtimeLong;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.UptimeMillisLong;
import android.app.BackgroundStartPrivileges;
import android.app.IApplicationThread;
import android.app.Notification;
@@ -677,52 +678,65 @@
* Data container class to help track certain fgs info for time-restricted types.
*/
static class TimeLimitedFgsInfo {
+ @UptimeMillisLong
+ private long mFirstFgsStartUptime;
+ // The first fgs start time is maintained here separately in realtime-base
+ // for the 24-hour window reset logic.
@ElapsedRealtimeLong
- private long mFirstFgsStartTime;
- @ElapsedRealtimeLong
+ private long mFirstFgsStartRealtime;
+ @UptimeMillisLong
private long mLastFgsStartTime;
- @ElapsedRealtimeLong
+ @UptimeMillisLong
private long mTimeLimitExceededAt = Long.MIN_VALUE;
+ @UptimeMillisLong
private long mTotalRuntime = 0;
- TimeLimitedFgsInfo(@ElapsedRealtimeLong long startTime) {
- mFirstFgsStartTime = startTime;
+ TimeLimitedFgsInfo(@UptimeMillisLong long startTime) {
+ mFirstFgsStartUptime = startTime;
+ mFirstFgsStartRealtime = SystemClock.elapsedRealtime();
mLastFgsStartTime = startTime;
}
- @ElapsedRealtimeLong
- public long getFirstFgsStartTime() {
- return mFirstFgsStartTime;
+ @UptimeMillisLong
+ public long getFirstFgsStartUptime() {
+ return mFirstFgsStartUptime;
}
- public void setLastFgsStartTime(@ElapsedRealtimeLong long startTime) {
+ @ElapsedRealtimeLong
+ public long getFirstFgsStartRealtime() {
+ return mFirstFgsStartRealtime;
+ }
+
+ public void setLastFgsStartTime(@UptimeMillisLong long startTime) {
mLastFgsStartTime = startTime;
}
- @ElapsedRealtimeLong
+ @UptimeMillisLong
public long getLastFgsStartTime() {
return mLastFgsStartTime;
}
public void updateTotalRuntime() {
- mTotalRuntime += SystemClock.elapsedRealtime() - mLastFgsStartTime;
+ mTotalRuntime += SystemClock.uptimeMillis() - mLastFgsStartTime;
}
+ @UptimeMillisLong
public long getTotalRuntime() {
return mTotalRuntime;
}
- public void setTimeLimitExceededAt(@ElapsedRealtimeLong long timeLimitExceededAt) {
+ public void setTimeLimitExceededAt(@UptimeMillisLong long timeLimitExceededAt) {
mTimeLimitExceededAt = timeLimitExceededAt;
}
- @ElapsedRealtimeLong
+ @UptimeMillisLong
public long getTimeLimitExceededAt() {
return mTimeLimitExceededAt;
}
public void reset() {
- mFirstFgsStartTime = 0;
+ mFirstFgsStartUptime = 0;
+ mFirstFgsStartRealtime = 0;
mLastFgsStartTime = 0;
mTotalRuntime = 0;
mTimeLimitExceededAt = Long.MIN_VALUE;
@@ -1858,8 +1872,8 @@
/**
* Called when a time-limited FGS starts.
*/
- public TimeLimitedFgsInfo createTimeLimitedFgsInfo(@ElapsedRealtimeLong long nowRealtime) {
- return new TimeLimitedFgsInfo(nowRealtime);
+ public TimeLimitedFgsInfo createTimeLimitedFgsInfo(@UptimeMillisLong long nowUptime) {
+ return new TimeLimitedFgsInfo(nowUptime);
}
/**
@@ -1872,27 +1886,6 @@
!= ServiceInfo.FOREGROUND_SERVICE_TYPE_NONE;
}
- /**
- * @return the next stop time for the given type, based on how long it has already ran for.
- * The total runtime is automatically reset 24hrs after the first fgs start of this type
- * or if the app has recently been in the TOP state when the app calls startForeground().
- */
- long getNextFgsStopTime(int fgsType, TimeLimitedFgsInfo fgsInfo) {
- final long timeLimit;
- switch (ams.mServices.getTimeLimitedFgsType(fgsType)) {
- case ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROCESSING:
- timeLimit = ams.mConstants.mMediaProcessingFgsTimeoutDuration;
- break;
- case ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC:
- timeLimit = ams.mConstants.mDataSyncFgsTimeoutDuration;
- break;
- // Add logic for time limits introduced in the future for other fgs types above.
- default:
- return Long.MAX_VALUE;
- }
- return fgsInfo.mLastFgsStartTime + Math.max(0, timeLimit - fgsInfo.mTotalRuntime);
- }
-
private boolean isAppAlive() {
if (app == null) {
return false;
diff --git a/services/core/java/com/android/server/audio/SpatializerHelper.java b/services/core/java/com/android/server/audio/SpatializerHelper.java
index 38fa79f..e2c4b46 100644
--- a/services/core/java/com/android/server/audio/SpatializerHelper.java
+++ b/services/core/java/com/android/server/audio/SpatializerHelper.java
@@ -88,6 +88,10 @@
/*package*/ static final SparseIntArray SPAT_MODE_FOR_DEVICE_TYPE = new SparseIntArray(14) {
{
append(AudioDeviceInfo.TYPE_BUILTIN_SPEAKER, Spatialization.Mode.TRANSAURAL);
+ // Speaker safe is considered compatible with spatial audio because routing media usage
+ // to speaker safe only happens in transient situations and should not affect app
+ // decisions to play spatial audio content.
+ append(AudioDeviceInfo.TYPE_BUILTIN_SPEAKER_SAFE, Spatialization.Mode.TRANSAURAL);
append(AudioDeviceInfo.TYPE_WIRED_HEADSET, Spatialization.Mode.BINAURAL);
append(AudioDeviceInfo.TYPE_WIRED_HEADPHONES, Spatialization.Mode.BINAURAL);
// assumption for A2DP: mostly headsets
@@ -805,7 +809,7 @@
private boolean isDeviceCompatibleWithSpatializationModes(@NonNull AudioDeviceAttributes ada) {
// modeForDevice will be neither transaural or binaural for devices that do not support
- // spatial audio. For instance mono devices like earpiece, speaker safe or sco must
+ // spatial audio. For instance mono devices like earpiece or sco must
// not be included.
final byte modeForDevice = (byte) SPAT_MODE_FOR_DEVICE_TYPE.get(ada.getType(),
/*default when type not found*/ -1);
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index f32c11d..8686e9a 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -250,8 +250,19 @@
private final Object mAssociationsLock = new Object();
@GuardedBy("mAssociationsLock")
private final Map<String, Integer> mRuntimeAssociations = new ArrayMap<>();
+
+ // The associations of input devices to displays by port. Maps from {InputDevice#mName} (String)
+ // to {DisplayInfo#uniqueId} (String) so that events from the Input Device go to a
+ // specific display.
@GuardedBy("mAssociationsLock")
private final Map<String, String> mUniqueIdAssociations = new ArrayMap<>();
+
+ // The associations of input devices to displays by descriptor. Maps from
+ // {InputDevice#mDescriptor} to {DisplayInfo#uniqueId} (String) so that events from the
+ // input device go to a specific display.
+ @GuardedBy("mAssociationsLock")
+ private final Map<String, String> mUniqueIdAssociationsByDescriptor = new ArrayMap<>();
+
// The map from input port (String) to the keyboard layout identifiers (comma separated string
// containing language tag and layout type) associated with the corresponding keyboard device.
// Currently only accessed by InputReader.
@@ -1741,8 +1752,8 @@
/**
* Add a runtime association between the input port and the display port. This overrides any
* static associations.
- * @param inputPort The port of the input device.
- * @param displayPort The physical port of the associated display.
+ * @param inputPort the port of the input device
+ * @param displayPort the physical port of the associated display
*/
@Override // Binder call
public void addPortAssociation(@NonNull String inputPort, int displayPort) {
@@ -1763,7 +1774,7 @@
/**
* Remove the runtime association between the input port and the display port. Any existing
* static association for the cleared input port will be restored.
- * @param inputPort The port of the input device to be cleared.
+ * @param inputPort the port of the input device to be cleared
*/
@Override // Binder call
public void removePortAssociation(@NonNull String inputPort) {
@@ -1813,6 +1824,49 @@
mNative.changeUniqueIdAssociation();
}
+ /**
+ * Adds a runtime association between the input device descriptor and the display unique id.
+ * @param inputDeviceDescriptor the descriptor of the input device
+ * @param displayUniqueId the unique ID of the display
+ */
+ @Override // Binder call
+ public void addUniqueIdAssociationByDescriptor(@NonNull String inputDeviceDescriptor,
+ @NonNull String displayUniqueId) {
+ if (!checkCallingPermission(
+ android.Manifest.permission.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY,
+ "addUniqueIdAssociationByDescriptor()")) {
+ throw new SecurityException(
+ "Requires ASSOCIATE_INPUT_DEVICE_TO_DISPLAY permission");
+ }
+
+ Objects.requireNonNull(inputDeviceDescriptor);
+ Objects.requireNonNull(displayUniqueId);
+ synchronized (mAssociationsLock) {
+ mUniqueIdAssociationsByDescriptor.put(inputDeviceDescriptor, displayUniqueId);
+ }
+ mNative.changeUniqueIdAssociation();
+ }
+
+ /**
+ * Removes the runtime association between the input device and the display.
+ * @param inputDeviceDescriptor the descriptor of the input device
+ */
+ @Override // Binder call
+ public void removeUniqueIdAssociationByDescriptor(@NonNull String inputDeviceDescriptor) {
+ if (!checkCallingPermission(
+ android.Manifest.permission.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY,
+ "removeUniqueIdAssociationByDescriptor()")) {
+ throw new SecurityException(
+ "Requires ASSOCIATE_INPUT_DEVICE_TO_DISPLAY permission");
+ }
+
+ Objects.requireNonNull(inputDeviceDescriptor);
+ synchronized (mAssociationsLock) {
+ mUniqueIdAssociationsByDescriptor.remove(inputDeviceDescriptor);
+ }
+ mNative.changeUniqueIdAssociation();
+ }
+
void setTypeAssociationInternal(@NonNull String inputPort, @NonNull String type) {
Objects.requireNonNull(inputPort);
Objects.requireNonNull(type);
@@ -2190,6 +2244,13 @@
pw.println(" uniqueId: " + v);
});
}
+ if (!mUniqueIdAssociationsByDescriptor.isEmpty()) {
+ pw.println("Unique Id Associations:");
+ mUniqueIdAssociationsByDescriptor.forEach((k, v) -> {
+ pw.print(" descriptor: " + k);
+ pw.println(" uniqueId: " + v);
+ });
+ }
if (!mDeviceTypeAssociations.isEmpty()) {
pw.println("Type Associations:");
mDeviceTypeAssociations.forEach((k, v) -> {
@@ -2633,6 +2694,17 @@
// Native callback
@SuppressWarnings("unused")
+ private String[] getInputUniqueIdAssociationsByDescriptor() {
+ final Map<String, String> associations;
+ synchronized (mAssociationsLock) {
+ associations = new HashMap<>(mUniqueIdAssociationsByDescriptor);
+ }
+
+ return flatten(associations);
+ }
+
+ // Native callback
+ @SuppressWarnings("unused")
@VisibleForTesting
String[] getDeviceTypeAssociations() {
final Map<String, String> associations;
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 7bd47f5..44a200e 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -6419,7 +6419,7 @@
nextEnabledImeIds[i] = nextEnabledImes.get(i).getId();
}
settings.putEnabledInputMethodsStr(InputMethodUtils.concatEnabledImeIds(
- settings.getEnabledInputMethodsStr(), nextEnabledImeIds));
+ "", nextEnabledImeIds));
// Reset selected IME.
settings.putSelectedInputMethod(nextIme);
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
index e5807e8..54303c0 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
@@ -1082,7 +1082,8 @@
int keyguardCredentialsType = lockPatternUtilsToKeyguardType(savedCredentialType);
try (LockscreenCredential credential =
createLockscreenCredential(keyguardCredentialsType, decryptedCredentials)) {
- // TODO(b/254335492): remove decryptedCredentials
+ Arrays.fill(decryptedCredentials, (byte) 0);
+ decryptedCredentials = null;
VerifyCredentialResponse verifyResponse =
lockSettingsService.verifyCredential(credential, userId, 0);
return handleVerifyCredentialResponse(verifyResponse, userId);
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index 74adf5e..f981d79 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -215,12 +215,6 @@
private final MediaCommunicationManager.SessionCallback mSession2TokenCallback =
new MediaCommunicationManager.SessionCallback() {
@Override
- // TODO (b/324266224): Deprecate this method once other overload is published.
- public void onSession2TokenCreated(Session2Token token) {
- addSession(token, Process.INVALID_PID);
- }
-
- @Override
public void onSession2TokenCreated(Session2Token token, int pid) {
addSession(token, pid);
}
diff --git a/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessorImpl.java b/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessorImpl.java
index 40353a2..f1248a3 100644
--- a/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessorImpl.java
+++ b/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessorImpl.java
@@ -435,7 +435,8 @@
@Override
public boolean isTelephonyTimeZoneDetectionFeatureSupported() {
- return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY);
+ return getConfigBoolean(com.android.internal.R.bool.config_enableTelephonyTimeZoneDetection)
+ && mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY);
}
@Override
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperCropper.java b/services/core/java/com/android/server/wallpaper/WallpaperCropper.java
index f6e0168..b19bc7d 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperCropper.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperCropper.java
@@ -99,15 +99,17 @@
/**
* Given the dimensions of the original wallpaper image, some optional suggested crops
- * (either defined by the user, or coming from a backup), and whether the device is RTL,
+ * (either defined by the user, or coming from a backup), and whether the device has RTL layout,
* generate a crop for the current display. This is done through the following process:
* <ul>
- * <li> If no suggested crops are provided, center the full image on the display. </li>
+ * <li> If no suggested crops are provided, in most cases render the full image left-aligned
+ * (or right-aligned if RTL) and use any additional width for parallax up to
+ * {@link #MAX_PARALLAX}. There are exceptions, see comments in "Case 1" of this function.
* <li> If there is a suggested crop the given displaySize, reuse the suggested crop and
- * adjust it using {@link #getAdjustedCrop}. </li>
+ * adjust it using {@link #getAdjustedCrop}.
* <li> If there are suggested crops, but not for the orientation of the given displaySize,
* reuse one of the suggested crop for another orientation and adjust if using
- * {@link #getAdjustedCrop}. </li>
+ * {@link #getAdjustedCrop}.
* </ul>
*
* @param displaySize The dimensions of the surface where we want to render the wallpaper
@@ -270,16 +272,12 @@
* Adjust a given crop:
* <ul>
* <li>If parallax = true, make sure we have a parallax of at most {@link #MAX_PARALLAX},
- * by removing content from the right (or left if RTL) if necessary.
- * </li>
+ * by removing content from the right (or left if RTL layout) if necessary.
* <li>If parallax = false, make sure we do not have additional width for parallax. If we
* have additional width for parallax, remove half of the additional width on both sides.
- * </li>
* <li>Make sure the crop fills the screen, i.e. that the width/height ratio of the crop
- * is at least the width/height ratio of the screen. If it is less, add width to the crop
- * (if possible on both sides) to fill the screen. If not enough width available, remove
- * height to the crop.
- * </li>
+ * is at least the width/height ratio of the screen. This is done accordingly to the
+ * {@code mode} used, which can be either {@link #ADD}, {@link #REMOVE} or {@link #BALANCE}.
* </ul>
*/
@VisibleForTesting
diff --git a/services/core/java/com/android/server/wm/CameraIdPackageNameBiMapping.java b/services/core/java/com/android/server/wm/CameraIdPackageNameBiMapping.java
new file mode 100644
index 0000000..d9730cb
--- /dev/null
+++ b/services/core/java/com/android/server/wm/CameraIdPackageNameBiMapping.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.util.ArrayMap;
+
+import java.util.Map;
+
+/**
+ * Bidirectional mapping (1:1) for the currently active cameraId and the app package that opened it.
+ *
+ * <p>This class is not thread-safe.
+ */
+final class CameraIdPackageNameBiMapping {
+ private final Map<String, String> mPackageToCameraIdMap = new ArrayMap<>();
+ private final Map<String, String> mCameraIdToPackageMap = new ArrayMap<>();
+
+ boolean isEmpty() {
+ return mCameraIdToPackageMap.isEmpty();
+ }
+
+ void put(@NonNull String packageName, @NonNull String cameraId) {
+ // Always using the last connected camera ID for the package even for the concurrent
+ // camera use case since we can't guess which camera is more important anyway.
+ removePackageName(packageName);
+ removeCameraId(cameraId);
+ mPackageToCameraIdMap.put(packageName, cameraId);
+ mCameraIdToPackageMap.put(cameraId, packageName);
+ }
+
+ boolean containsPackageName(@NonNull String packageName) {
+ return mPackageToCameraIdMap.containsKey(packageName);
+ }
+
+ @Nullable
+ String getCameraId(@NonNull String packageName) {
+ return mPackageToCameraIdMap.get(packageName);
+ }
+
+ void removeCameraId(@NonNull String cameraId) {
+ final String packageName = mCameraIdToPackageMap.get(cameraId);
+ if (packageName == null) {
+ return;
+ }
+ mPackageToCameraIdMap.remove(packageName, cameraId);
+ mCameraIdToPackageMap.remove(cameraId, packageName);
+ }
+
+ @NonNull
+ String getSummaryForDisplayRotationHistoryRecord() {
+ return "{ mPackageToCameraIdMap=" + mPackageToCameraIdMap + " }";
+ }
+
+ private void removePackageName(@NonNull String packageName) {
+ String cameraId = mPackageToCameraIdMap.get(packageName);
+ if (cameraId == null) {
+ return;
+ }
+ mPackageToCameraIdMap.remove(packageName, cameraId);
+ mCameraIdToPackageMap.remove(cameraId, packageName);
+ }
+}
diff --git a/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java b/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java
index e808dec..c8a7ef1 100644
--- a/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java
@@ -46,7 +46,6 @@
import android.hardware.camera2.CameraManager;
import android.os.Handler;
import android.os.RemoteException;
-import android.util.ArrayMap;
import android.util.ArraySet;
import android.widget.Toast;
@@ -56,7 +55,6 @@
import com.android.internal.protolog.common.ProtoLog;
import com.android.server.UiThread;
-import java.util.Map;
import java.util.Set;
/**
@@ -100,7 +98,8 @@
// camera id by a package name when determining rotation; 2) get a package name by a camera id
// when camera connection is closed and we need to clean up our records.
@GuardedBy("this")
- private final CameraIdPackageNameBiMap mCameraIdPackageBiMap = new CameraIdPackageNameBiMap();
+ private final CameraIdPackageNameBiMapping mCameraIdPackageBiMap =
+ new CameraIdPackageNameBiMapping();
@GuardedBy("this")
private final Set<String> mScheduledToBeRemovedCameraIdSet = new ArraySet<>();
@GuardedBy("this")
@@ -516,54 +515,4 @@
}
return topActivity.mLetterboxUiController.isRefreshAfterRotationRequested();
}
-
- private static class CameraIdPackageNameBiMap {
-
- private final Map<String, String> mPackageToCameraIdMap = new ArrayMap<>();
- private final Map<String, String> mCameraIdToPackageMap = new ArrayMap<>();
-
- boolean isEmpty() {
- return mCameraIdToPackageMap.isEmpty();
- }
-
- void put(String packageName, String cameraId) {
- // Always using the last connected camera ID for the package even for the concurrent
- // camera use case since we can't guess which camera is more important anyway.
- removePackageName(packageName);
- removeCameraId(cameraId);
- mPackageToCameraIdMap.put(packageName, cameraId);
- mCameraIdToPackageMap.put(cameraId, packageName);
- }
-
- boolean containsPackageName(String packageName) {
- return mPackageToCameraIdMap.containsKey(packageName);
- }
-
- @Nullable
- String getCameraId(String packageName) {
- return mPackageToCameraIdMap.get(packageName);
- }
-
- void removeCameraId(String cameraId) {
- String packageName = mCameraIdToPackageMap.get(cameraId);
- if (packageName == null) {
- return;
- }
- mPackageToCameraIdMap.remove(packageName, cameraId);
- mCameraIdToPackageMap.remove(cameraId, packageName);
- }
-
- String getSummaryForDisplayRotationHistoryRecord() {
- return "{ mPackageToCameraIdMap=" + mPackageToCameraIdMap + " }";
- }
-
- private void removePackageName(String packageName) {
- String cameraId = mPackageToCameraIdMap.get(packageName);
- if (cameraId == null) {
- return;
- }
- mPackageToCameraIdMap.remove(packageName, cameraId);
- mCameraIdToPackageMap.remove(cameraId, packageName);
- }
- }
}
diff --git a/services/core/jni/OWNERS b/services/core/jni/OWNERS
index 736b051..25c5db1 100644
--- a/services/core/jni/OWNERS
+++ b/services/core/jni/OWNERS
@@ -34,3 +34,6 @@
# Bug component : 158088 = per-file *AnrTimer*
per-file *AnrTimer* = file:/PERFORMANCE_OWNERS
+
+# HintManagerService
+per-file com_android_server_hint_HintManagerService.cpp = file:/ADPF_OWNERS
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 88c47f3..553f721 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -129,6 +129,7 @@
jmethodID getExcludedDeviceNames;
jmethodID getInputPortAssociations;
jmethodID getInputUniqueIdAssociations;
+ jmethodID getInputUniqueIdAssociationsByDescriptor;
jmethodID getDeviceTypeAssociations;
jmethodID getKeyboardLayoutAssociations;
jmethodID getHoverTapTimeout;
@@ -634,11 +635,15 @@
env->DeleteLocalRef(portAssociations);
}
- outConfig->uniqueIdAssociations =
+ outConfig->uniqueIdAssociationsByPort =
readMapFromInterleavedJavaArray<std::string>(gServiceClassInfo
.getInputUniqueIdAssociations,
"getInputUniqueIdAssociations");
+ outConfig->uniqueIdAssociationsByDescriptor = readMapFromInterleavedJavaArray<
+ std::string>(gServiceClassInfo.getInputUniqueIdAssociationsByDescriptor,
+ "getInputUniqueIdAssociationsByDescriptor");
+
outConfig->deviceTypeAssociations =
readMapFromInterleavedJavaArray<std::string>(gServiceClassInfo
.getDeviceTypeAssociations,
@@ -3093,6 +3098,9 @@
GET_METHOD_ID(gServiceClassInfo.getInputUniqueIdAssociations, clazz,
"getInputUniqueIdAssociations", "()[Ljava/lang/String;");
+ GET_METHOD_ID(gServiceClassInfo.getInputUniqueIdAssociationsByDescriptor, clazz,
+ "getInputUniqueIdAssociationsByDescriptor", "()[Ljava/lang/String;");
+
GET_METHOD_ID(gServiceClassInfo.getDeviceTypeAssociations, clazz, "getDeviceTypeAssociations",
"()[Ljava/lang/String;");
diff --git a/services/tests/InputMethodSystemServerTests/test-apps/SimpleTestIme/src/com/android/apps/inputmethod/simpleime/testing/TestActivity.java b/services/tests/InputMethodSystemServerTests/test-apps/SimpleTestIme/src/com/android/apps/inputmethod/simpleime/testing/TestActivity.java
index 73b4501..37b05ff 100644
--- a/services/tests/InputMethodSystemServerTests/test-apps/SimpleTestIme/src/com/android/apps/inputmethod/simpleime/testing/TestActivity.java
+++ b/services/tests/InputMethodSystemServerTests/test-apps/SimpleTestIme/src/com/android/apps/inputmethod/simpleime/testing/TestActivity.java
@@ -77,6 +77,7 @@
mEditText = new EditText(this);
mEditText.setContentDescription("Input box");
rootView.addView(mEditText, new LinearLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT));
+ rootView.setFitsSystemWindows(true);
setContentView(rootView);
mEditText.requestFocus();
sLastCreatedInstance = new WeakReference<>(this);
diff --git a/services/tests/mockingservicestests/src/com/android/server/alarm/UserWakeupStoreTest.java b/services/tests/mockingservicestests/src/com/android/server/alarm/UserWakeupStoreTest.java
index 5d3e499..75e8e68 100644
--- a/services/tests/mockingservicestests/src/com/android/server/alarm/UserWakeupStoreTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/alarm/UserWakeupStoreTest.java
@@ -116,7 +116,7 @@
mUserWakeupStore.addUserWakeup(USER_ID_1, TEST_TIMESTAMP - 7_000);
mUserWakeupStore.addUserWakeup(USER_ID_1, finalAlarmTime);
assertEquals(1, mUserWakeupStore.getUserIdsToWakeup(TEST_TIMESTAMP).length);
- final long alarmTime = mUserWakeupStore.getWakeupTimeForUserForTest(USER_ID_1)
+ final long alarmTime = mUserWakeupStore.getWakeupTimeForUser(USER_ID_1)
+ BUFFER_TIME_MS;
assertTrue(finalAlarmTime + USER_START_TIME_DEVIATION_LIMIT_MS >= alarmTime);
assertTrue(finalAlarmTime - USER_START_TIME_DEVIATION_LIMIT_MS <= alarmTime);
@@ -129,8 +129,8 @@
mUserWakeupStore.addUserWakeup(USER_ID_3, TEST_TIMESTAMP - 13_000);
assertEquals(3, mUserWakeupStore.getUserIdsToWakeup(TEST_TIMESTAMP).length);
mUserWakeupStore.removeUserWakeup(USER_ID_3);
- assertEquals(-1, mUserWakeupStore.getWakeupTimeForUserForTest(USER_ID_3));
- assertTrue(mUserWakeupStore.getWakeupTimeForUserForTest(USER_ID_2) > 0);
+ assertEquals(-1, mUserWakeupStore.getWakeupTimeForUser(USER_ID_3));
+ assertTrue(mUserWakeupStore.getWakeupTimeForUser(USER_ID_2) > 0);
}
@Test
@@ -139,10 +139,10 @@
mUserWakeupStore.addUserWakeup(USER_ID_2, TEST_TIMESTAMP - 3_000);
mUserWakeupStore.addUserWakeup(USER_ID_3, TEST_TIMESTAMP - 13_000);
assertEquals(mUserWakeupStore.getNextWakeupTime(),
- mUserWakeupStore.getWakeupTimeForUserForTest(USER_ID_1));
+ mUserWakeupStore.getWakeupTimeForUser(USER_ID_1));
mUserWakeupStore.removeUserWakeup(USER_ID_1);
assertEquals(mUserWakeupStore.getNextWakeupTime(),
- mUserWakeupStore.getWakeupTimeForUserForTest(USER_ID_3));
+ mUserWakeupStore.getWakeupTimeForUser(USER_ID_3));
}
@Test
@@ -154,16 +154,16 @@
mUserWakeupStore.init();
final long realtime = SystemClock.elapsedRealtime();
assertEquals(0, mUserWakeupStore.getUserIdsToWakeup(TEST_TIMESTAMP).length);
- assertTrue(mUserWakeupStore.getWakeupTimeForUserForTest(USER_ID_2) > realtime);
- assertTrue(mUserWakeupStore.getWakeupTimeForUserForTest(USER_ID_1)
- < mUserWakeupStore.getWakeupTimeForUserForTest(USER_ID_3));
- assertTrue(mUserWakeupStore.getWakeupTimeForUserForTest(USER_ID_3)
- < mUserWakeupStore.getWakeupTimeForUserForTest(USER_ID_2));
- assertTrue(mUserWakeupStore.getWakeupTimeForUserForTest(USER_ID_1) - realtime
+ assertTrue(mUserWakeupStore.getWakeupTimeForUser(USER_ID_2) > realtime);
+ assertTrue(mUserWakeupStore.getWakeupTimeForUser(USER_ID_1)
+ < mUserWakeupStore.getWakeupTimeForUser(USER_ID_3));
+ assertTrue(mUserWakeupStore.getWakeupTimeForUser(USER_ID_3)
+ < mUserWakeupStore.getWakeupTimeForUser(USER_ID_2));
+ assertTrue(mUserWakeupStore.getWakeupTimeForUser(USER_ID_1) - realtime
< BUFFER_TIME_MS + USER_START_TIME_DEVIATION_LIMIT_MS);
- assertTrue(mUserWakeupStore.getWakeupTimeForUserForTest(USER_ID_3) - realtime
+ assertTrue(mUserWakeupStore.getWakeupTimeForUser(USER_ID_3) - realtime
< 2 * BUFFER_TIME_MS + USER_START_TIME_DEVIATION_LIMIT_MS);
- assertTrue(mUserWakeupStore.getWakeupTimeForUserForTest(USER_ID_2) - realtime
+ assertTrue(mUserWakeupStore.getWakeupTimeForUser(USER_ID_2) - realtime
< 3 * BUFFER_TIME_MS + USER_START_TIME_DEVIATION_LIMIT_MS);
}
//TODO: b/330264023 - Add tests for I/O in usersWithAlarmClocks.xml.
diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/InputManagerMockHelper.java b/services/tests/servicestests/src/com/android/server/companion/virtual/InputManagerMockHelper.java
index 74e854e4..b33a8aa 100644
--- a/services/tests/servicestests/src/com/android/server/companion/virtual/InputManagerMockHelper.java
+++ b/services/tests/servicestests/src/com/android/server/companion/virtual/InputManagerMockHelper.java
@@ -79,8 +79,9 @@
when(mIInputManagerMock.getInputDeviceIds()).thenReturn(new int[0]);
doAnswer(inv -> mDevices.get(inv.getArgument(0)))
.when(mIInputManagerMock).getInputDevice(anyInt());
- doAnswer(inv -> mUniqueIdAssociation.put(inv.getArgument(0), inv.getArgument(1))).when(
- mIInputManagerMock).addUniqueIdAssociation(anyString(), anyString());
+ doAnswer(inv -> mUniqueIdAssociation.put(inv.getArgument(0),
+ inv.getArgument(1))).when(mIInputManagerMock).addUniqueIdAssociation(
+ anyString(), anyString());
doAnswer(inv -> mUniqueIdAssociation.remove(inv.getArgument(0))).when(
mIInputManagerMock).removeUniqueIdAssociation(anyString());
diff --git a/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
index a911131..ab8c53c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
@@ -53,6 +53,7 @@
import android.content.pm.ApplicationInfo;
import android.content.res.Resources;
import android.os.Bundle;
+import android.os.Looper;
import android.os.RemoteCallback;
import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
@@ -531,7 +532,7 @@
Task task = createTopTaskWithActivity();
WindowState appWindow = task.getTopVisibleAppMainWindow();
WindowOnBackInvokedDispatcher dispatcher =
- new WindowOnBackInvokedDispatcher(context);
+ new WindowOnBackInvokedDispatcher(context, Looper.getMainLooper());
spyOn(appWindow.mSession);
doAnswer(invocation -> {
appWindow.setOnBackInvokedCallbackInfo(invocation.getArgument(1));
@@ -742,6 +743,10 @@
@Override
public void onBackInvoked() {
}
+
+ @Override
+ public void setTriggerBack(boolean triggerBack) {
+ }
};
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/CameraIdPackageNameBiMappingTests.java b/services/tests/wmtests/src/com/android/server/wm/CameraIdPackageNameBiMappingTests.java
new file mode 100644
index 0000000..f3a20a6
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/wm/CameraIdPackageNameBiMappingTests.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Tests for {@link CameraIdPackageNameBiMapping}.
+ *
+ * Build/Install/Run:
+ * atest WmTests:CameraIdPackageNameBiMapTests
+ */
+@SmallTest
+@Presubmit
+public class CameraIdPackageNameBiMappingTests {
+ private CameraIdPackageNameBiMapping mMapping;
+
+ private static final String PACKAGE_1 = "PACKAGE_1";
+ private static final String PACKAGE_2 = "PACKAGE_2";
+ private static final String CAMERA_ID_1 = "1234";
+ private static final String CAMERA_ID_2 = "5678";
+
+ @Before
+ public void setUp() {
+ mMapping = new CameraIdPackageNameBiMapping();
+ }
+
+ @Test
+ public void mappingEmptyAtStart() {
+ assertTrue(mMapping.isEmpty());
+ }
+
+ @Test
+ public void addPackageAndId_containsPackage() {
+ mMapping.put(PACKAGE_1, CAMERA_ID_1);
+ assertTrue(mMapping.containsPackageName(PACKAGE_1));
+ }
+
+ @Test
+ public void addTwoPackagesAndId_containsPackages() {
+ mMapping.put(PACKAGE_1, CAMERA_ID_1);
+ mMapping.put(PACKAGE_2, CAMERA_ID_2);
+ assertTrue(mMapping.containsPackageName(PACKAGE_1));
+ assertTrue(mMapping.containsPackageName(PACKAGE_2));
+ }
+
+ @Test
+ public void addPackageAndId_mapContainsPackageAndId() {
+ mMapping.put(PACKAGE_1, CAMERA_ID_1);
+ assertEquals(CAMERA_ID_1, mMapping.getCameraId(PACKAGE_1));
+ }
+
+ @Test
+ public void changeCameraId_newestCameraId() {
+ mMapping.put(PACKAGE_1, CAMERA_ID_1);
+ mMapping.put(PACKAGE_1, CAMERA_ID_2);
+ assertEquals(CAMERA_ID_2, mMapping.getCameraId(PACKAGE_1));
+ }
+
+ @Test
+ public void changePackage_newestPackage() {
+ mMapping.put(PACKAGE_1, CAMERA_ID_1);
+ mMapping.put(PACKAGE_2, CAMERA_ID_1);
+ assertFalse(mMapping.containsPackageName(PACKAGE_1));
+ assertTrue(mMapping.containsPackageName(PACKAGE_2));
+ assertEquals(CAMERA_ID_1, mMapping.getCameraId(PACKAGE_2));
+ }
+
+ @Test
+ public void addAndRemoveCameraId_containsOtherPackage() {
+ mMapping.put(PACKAGE_1, CAMERA_ID_1);
+ mMapping.put(PACKAGE_2, CAMERA_ID_2);
+ mMapping.removeCameraId(CAMERA_ID_1);
+ assertFalse(mMapping.containsPackageName(PACKAGE_1));
+ assertTrue(mMapping.containsPackageName(PACKAGE_2));
+ }
+
+ @Test
+ public void addAndRemoveOnlyCameraId_empty() {
+ mMapping.put(PACKAGE_1, CAMERA_ID_1);
+ mMapping.removeCameraId(CAMERA_ID_1);
+ assertTrue(mMapping.isEmpty());
+ }
+}
diff --git a/tests/Input/src/com/android/server/input/InputManagerServiceTests.kt b/tests/Input/src/com/android/server/input/InputManagerServiceTests.kt
index f6f766a..c9c6574 100644
--- a/tests/Input/src/com/android/server/input/InputManagerServiceTests.kt
+++ b/tests/Input/src/com/android/server/input/InputManagerServiceTests.kt
@@ -19,17 +19,26 @@
import android.content.Context
import android.content.ContextWrapper
+import android.hardware.display.DisplayManager
import android.hardware.display.DisplayViewport
+import android.hardware.display.VirtualDisplay
import android.hardware.input.InputManager
import android.hardware.input.InputManagerGlobal
+import android.os.InputEventInjectionSync
+import android.os.SystemClock
import android.os.test.TestLooper
import android.platform.test.annotations.Presubmit
import android.platform.test.annotations.RequiresFlagsDisabled
import android.platform.test.flag.junit.DeviceFlagsValueProvider
import android.provider.Settings
-import android.test.mock.MockContentResolver
+import android.view.View.OnKeyListener
import android.view.Display
+import android.view.InputDevice
+import android.view.KeyEvent
import android.view.PointerIcon
+import android.view.SurfaceHolder
+import android.view.SurfaceView
+import android.test.mock.MockContentResolver
import androidx.test.platform.app.InstrumentationRegistry
import com.android.internal.util.test.FakeSettingsProvider
import com.google.common.truth.Truth.assertThat
@@ -48,6 +57,7 @@
import org.mockito.Mockito.`when`
import org.mockito.Mockito.clearInvocations
import org.mockito.Mockito.doAnswer
+import org.mockito.Mockito.mock
import org.mockito.Mockito.never
import org.mockito.Mockito.spy
import org.mockito.Mockito.times
@@ -412,6 +422,175 @@
verify(wmCallbacks).notifyPointerDisplayIdChanged(overrideDisplayId, 0f, 0f)
thread.join(100 /*millis*/)
}
+
+ private fun createVirtualDisplays(count: Int): List<VirtualDisplay> {
+ val displayManager: DisplayManager = context.getSystemService(
+ DisplayManager::class.java
+ ) as DisplayManager
+ val virtualDisplays = mutableListOf<VirtualDisplay>()
+ for (i in 0 until count) {
+ virtualDisplays.add(displayManager.createVirtualDisplay(
+ /* displayName= */ "testVirtualDisplay$i",
+ /* width= */ 100,
+ /* height= */ 100,
+ /* densityDpi= */ 100,
+ /* surface= */ null,
+ /* flags= */ 0
+ ))
+ }
+ return virtualDisplays
+ }
+
+ // Helper function that creates a KeyEvent with Keycode A with the given action
+ private fun createKeycodeAEvent(inputDevice: InputDevice, action: Int): KeyEvent {
+ val eventTime = SystemClock.uptimeMillis()
+ return KeyEvent(
+ /* downTime= */ eventTime,
+ /* eventTime= */ eventTime,
+ /* action= */ action,
+ /* code= */ KeyEvent.KEYCODE_A,
+ /* repeat= */ 0,
+ /* metaState= */ 0,
+ /* deviceId= */ inputDevice.id,
+ /* scanCode= */ 0,
+ /* flags= */ KeyEvent.FLAG_FROM_SYSTEM,
+ /* source= */ InputDevice.SOURCE_KEYBOARD
+ )
+ }
+
+ private fun createInputDevice(): InputDevice {
+ return InputDevice.Builder()
+ .setId(123)
+ .setName("abc")
+ .setDescriptor("def")
+ .setSources(InputDevice.SOURCE_KEYBOARD)
+ .build()
+ }
+
+ @Test
+ fun addUniqueIdAssociationByDescriptor_verifyAssociations() {
+ // Overall goal is to have 2 displays and verify that events from the InputDevice are
+ // sent only to the view that is on the associated display.
+ // So, associate the InputDevice with display 1, then send and verify KeyEvents.
+ // Then remove associations, then associate the InputDevice with display 2, then send
+ // and verify commands.
+
+ // Make 2 virtual displays with some mock SurfaceViews
+ val mockSurfaceView1 = mock(SurfaceView::class.java)
+ val mockSurfaceView2 = mock(SurfaceView::class.java)
+ val mockSurfaceHolder1 = mock(SurfaceHolder::class.java)
+ `when`(mockSurfaceView1.holder).thenReturn(mockSurfaceHolder1)
+ val mockSurfaceHolder2 = mock(SurfaceHolder::class.java)
+ `when`(mockSurfaceView2.holder).thenReturn(mockSurfaceHolder2)
+
+ val virtualDisplays = createVirtualDisplays(2)
+
+ // Simulate an InputDevice
+ val inputDevice = createInputDevice()
+
+ // Associate input device with display
+ service.addUniqueIdAssociationByDescriptor(
+ inputDevice.descriptor,
+ virtualDisplays[0].display.displayId.toString()
+ )
+
+ // Simulate 2 different KeyEvents
+ val downEvent = createKeycodeAEvent(inputDevice, KeyEvent.ACTION_DOWN)
+ val upEvent = createKeycodeAEvent(inputDevice, KeyEvent.ACTION_UP)
+
+ // Create a mock OnKeyListener object
+ val mockOnKeyListener = mock(OnKeyListener::class.java)
+
+ // Verify that the event went to Display 1 not Display 2
+ service.injectInputEvent(downEvent, InputEventInjectionSync.NONE)
+
+ // Call the onKey method on the mock OnKeyListener object
+ mockOnKeyListener.onKey(mockSurfaceView1, /* keyCode= */ KeyEvent.KEYCODE_A, downEvent)
+ mockOnKeyListener.onKey(mockSurfaceView2, /* keyCode= */ KeyEvent.KEYCODE_A, upEvent)
+
+ // Verify that the onKey method was called with the expected arguments
+ verify(mockOnKeyListener).onKey(mockSurfaceView1, KeyEvent.KEYCODE_A, downEvent)
+ verify(mockOnKeyListener, never()).onKey(mockSurfaceView2, KeyEvent.KEYCODE_A, downEvent)
+
+ // Remove association
+ service.removeUniqueIdAssociationByDescriptor(inputDevice.descriptor)
+
+ // Associate with Display 2
+ service.addUniqueIdAssociationByDescriptor(
+ inputDevice.descriptor,
+ virtualDisplays[1].display.displayId.toString()
+ )
+
+ // Simulate a KeyEvent
+ service.injectInputEvent(upEvent, InputEventInjectionSync.NONE)
+
+ // Verify that the event went to Display 2 not Display 1
+ verify(mockOnKeyListener).onKey(mockSurfaceView2, KeyEvent.KEYCODE_A, upEvent)
+ verify(mockOnKeyListener, never()).onKey(mockSurfaceView1, KeyEvent.KEYCODE_A, upEvent)
+ }
+
+ // TODO(b/324075859): Rename this method to addUniqueIdAssociationByPort_verifyAssociations
+ @Test
+ fun addUniqueIdAssociation_verifyAssociations() {
+ // Overall goal is to have 2 displays and verify that events from the InputDevice are
+ // sent only to the view that is on the associated display.
+ // So, associate the InputDevice with display 1, then send and verify KeyEvents.
+ // Then remove associations, then associate the InputDevice with display 2, then send
+ // and verify commands.
+
+ // Make 2 virtual displays with some mock SurfaceViews
+ val mockSurfaceView1 = mock(SurfaceView::class.java)
+ val mockSurfaceView2 = mock(SurfaceView::class.java)
+ val mockSurfaceHolder1 = mock(SurfaceHolder::class.java)
+ `when`(mockSurfaceView1.holder).thenReturn(mockSurfaceHolder1)
+ val mockSurfaceHolder2 = mock(SurfaceHolder::class.java)
+ `when`(mockSurfaceView2.holder).thenReturn(mockSurfaceHolder2)
+
+ val virtualDisplays = createVirtualDisplays(2)
+
+ // Simulate an InputDevice
+ val inputDevice = createInputDevice()
+
+ // Associate input device with display
+ service.addUniqueIdAssociation(
+ inputDevice.name,
+ virtualDisplays[0].display.displayId.toString()
+ )
+
+ // Simulate 2 different KeyEvents
+ val downEvent = createKeycodeAEvent(inputDevice, KeyEvent.ACTION_DOWN)
+ val upEvent = createKeycodeAEvent(inputDevice, KeyEvent.ACTION_UP)
+
+ // Create a mock OnKeyListener object
+ val mockOnKeyListener = mock(OnKeyListener::class.java)
+
+ // Verify that the event went to Display 1 not Display 2
+ service.injectInputEvent(downEvent, InputEventInjectionSync.NONE)
+
+ // Call the onKey method on the mock OnKeyListener object
+ mockOnKeyListener.onKey(mockSurfaceView1, /* keyCode= */ KeyEvent.KEYCODE_A, downEvent)
+ mockOnKeyListener.onKey(mockSurfaceView2, /* keyCode= */ KeyEvent.KEYCODE_A, upEvent)
+
+ // Verify that the onKey method was called with the expected arguments
+ verify(mockOnKeyListener).onKey(mockSurfaceView1, KeyEvent.KEYCODE_A, downEvent)
+ verify(mockOnKeyListener, never()).onKey(mockSurfaceView2, KeyEvent.KEYCODE_A, downEvent)
+
+ // Remove association
+ service.removeUniqueIdAssociation(inputDevice.name)
+
+ // Associate with Display 2
+ service.addUniqueIdAssociation(
+ inputDevice.name,
+ virtualDisplays[1].display.displayId.toString()
+ )
+
+ // Simulate a KeyEvent
+ service.injectInputEvent(upEvent, InputEventInjectionSync.NONE)
+
+ // Verify that the event went to Display 2 not Display 1
+ verify(mockOnKeyListener).onKey(mockSurfaceView2, KeyEvent.KEYCODE_A, upEvent)
+ verify(mockOnKeyListener, never()).onKey(mockSurfaceView1, KeyEvent.KEYCODE_A, upEvent)
+ }
}
private fun <T> whenever(methodCall: T): OngoingStubbing<T> = `when`(methodCall)
diff --git a/tests/MultiDeviceInput/src/test/multideviceinput/DrawingView.kt b/tests/MultiDeviceInput/src/test/multideviceinput/DrawingView.kt
index b5bd9ca..8bc2f97 100644
--- a/tests/MultiDeviceInput/src/test/multideviceinput/DrawingView.kt
+++ b/tests/MultiDeviceInput/src/test/multideviceinput/DrawingView.kt
@@ -21,8 +21,13 @@
import android.graphics.Color
import android.graphics.Paint
import android.util.AttributeSet
+import android.view.InputDevice
+import android.view.InputDevice.SOURCE_MOUSE
import android.view.InputDevice.SOURCE_STYLUS
+import android.view.InputDevice.SOURCE_TOUCHSCREEN
+import android.view.InputDevice.SOURCE_TOUCHPAD
import android.view.MotionEvent
+import android.view.MotionEvent.ACTION_CANCEL
import android.view.MotionEvent.ACTION_DOWN
import android.view.MotionEvent.ACTION_HOVER_EXIT
import android.view.MotionEvent.ACTION_UP
@@ -56,8 +61,8 @@
}
private fun drawCircle(canvas: Canvas, event: MotionEvent, paint: Paint, radius: Float) {
- val x = event.getX()
- val y = event.getY()
+ val x = event.x
+ val y = event.y
canvas.drawCircle(x, y, radius, paint)
}
@@ -110,44 +115,72 @@
private val scaleGestureDetector = ScaleGestureDetector(context, scaleGestureListener, null)
private var touchPaint = Paint()
+ private var touchpadPaint = Paint()
private var stylusPaint = Paint()
+ private var mousePaint = Paint()
+ private var drawingTabletPaint = Paint()
private fun init() {
touchPaint.color = Color.RED
- touchPaint.setStrokeWidth(5f)
+ touchPaint.strokeWidth = 5f
+ touchpadPaint.color = Color.BLACK
+ touchpadPaint.strokeWidth = 5f
stylusPaint.color = Color.YELLOW
- stylusPaint.setStrokeWidth(5f)
-
+ stylusPaint.strokeWidth = 5f
+ mousePaint.color = Color.BLUE
+ mousePaint.strokeWidth = 5f
+ drawingTabletPaint.color = Color.GREEN
+ drawingTabletPaint.strokeWidth = 5f
setOnHoverListener { _, event -> processHoverEvent(event); true }
}
+ private fun resolvePaint(event: MotionEvent): Paint? {
+ val inputDevice = InputDevice.getDevice(event.deviceId)
+ val isTouchpadDevice = inputDevice != null && inputDevice.supportsSource(SOURCE_TOUCHPAD)
+ return if (event.isFromSource(SOURCE_STYLUS or SOURCE_MOUSE)) {
+ // External stylus / drawing tablet
+ drawingTabletPaint
+ } else if (event.isFromSource(SOURCE_TOUCHSCREEN) && !event.isFromSource(SOURCE_STYLUS)) {
+ // Touchscreen event
+ touchPaint
+ } else if (event.isFromSource(SOURCE_MOUSE) &&
+ (event.isFromSource(SOURCE_TOUCHPAD) || isTouchpadDevice)) {
+ // Touchpad event
+ touchpadPaint
+ } else if (event.isFromSource(SOURCE_MOUSE)) {
+ // Mouse event
+ mousePaint
+ } else if (event.isFromSource(SOURCE_STYLUS)) {
+ // Stylus event
+ stylusPaint
+ } else {
+ // Drop the event
+ null
+ }
+ }
+
private fun processTouchEvent(event: MotionEvent) {
scaleGestureDetector.onTouchEvent(event)
if (event.actionMasked == ACTION_DOWN) {
touchEvents.remove(event.deviceId)
myState?.state = PointerState.DOWN
- } else if (event.actionMasked == ACTION_UP) {
+ } else if (event.actionMasked == ACTION_UP || event.actionMasked == ACTION_CANCEL) {
myState?.state = PointerState.NONE
}
- var vec = touchEvents.getOrPut(event.deviceId) { Vector<Pair<MotionEvent, Paint>>() }
-
- val paint = if (event.isFromSource(SOURCE_STYLUS)) {
+ val paint = resolvePaint(event)
+ if (paint != null) {
+ val vec = touchEvents.getOrPut(event.deviceId) { Vector<Pair<MotionEvent, Paint>>() }
val size = myState?.lineSize ?: 5f
- stylusPaint.setStrokeWidth(size)
- Paint(stylusPaint)
- } else {
- val size = myState?.lineSize ?: 5f
- touchPaint.setStrokeWidth(size)
- Paint(touchPaint)
+ paint.strokeWidth = size
+ vec.add(Pair(MotionEvent.obtain(event), Paint(paint)))
+ invalidate()
}
- vec.add(Pair(MotionEvent.obtain(event), paint))
- invalidate()
}
private fun processHoverEvent(event: MotionEvent) {
hoverEvents.remove(event.deviceId)
- if (event.getActionMasked() != ACTION_HOVER_EXIT) {
- hoverEvents.put(event.deviceId, MotionEvent.obtain(event))
+ if (event.actionMasked != ACTION_HOVER_EXIT) {
+ hoverEvents[event.deviceId] = MotionEvent.obtain(event)
myState?.state = PointerState.HOVER
} else {
myState?.state = PointerState.NONE
@@ -155,7 +188,7 @@
invalidate()
}
- public override fun onTouchEvent(event: MotionEvent): Boolean {
+ override fun onTouchEvent(event: MotionEvent): Boolean {
processTouchEvent(event)
return true
}
@@ -171,12 +204,10 @@
}
// Draw hovers
for ((_, event) in hoverEvents ) {
- if (event.isFromSource(SOURCE_STYLUS)) {
+ val paint = resolvePaint(event)
+ if (paint != null) {
val size = myState?.circleSize ?: 20f
- drawCircle(canvas, event, stylusPaint, size)
- } else {
- val size = myState?.circleSize ?: 20f
- drawCircle(canvas, event, touchPaint, size)
+ drawCircle(canvas, event, paint, size)
}
}
}
diff --git a/tests/testables/src/android/testing/ViewUtils.java b/tests/testables/src/android/testing/ViewUtils.java
index 80c2e8d..0fad79d 100644
--- a/tests/testables/src/android/testing/ViewUtils.java
+++ b/tests/testables/src/android/testing/ViewUtils.java
@@ -31,13 +31,20 @@
* This is currently done by adding the view to a window.
*/
public static void attachView(View view) {
+ attachView(view, LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
+ }
+
+ /**
+ * Causes the view (and its children) to have {@link View#onAttachedToWindow()} called.
+ *
+ * This is currently done by adding the view to a window.
+ */
+ public static void attachView(View view, int width, int height) {
// Make sure hardware acceleration isn't turned on.
view.getContext().getApplicationInfo().flags &=
~(ApplicationInfo.FLAG_HARDWARE_ACCELERATED);
- WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
- LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT,
- LayoutParams.TYPE_APPLICATION_OVERLAY,
- 0, PixelFormat.TRANSLUCENT);
+ WindowManager.LayoutParams lp = new WindowManager.LayoutParams(width, height,
+ LayoutParams.TYPE_APPLICATION_OVERLAY, 0, PixelFormat.TRANSLUCENT);
view.getContext().getSystemService(WindowManager.class).addView(view, lp);
}
diff --git a/tools/aapt/SdkConstants.h b/tools/aapt/SdkConstants.h
index e2c1614..ebb82ce 100644
--- a/tools/aapt/SdkConstants.h
+++ b/tools/aapt/SdkConstants.h
@@ -50,6 +50,7 @@
SDK_S_V2 = 32,
SDK_TIRAMISU = 33,
SDK_UPSIDE_DOWN_CAKE = 34,
+ SDK_VANILLA_ICE_CREAM = 35,
SDK_CUR_DEVELOPMENT = 10000,
};
diff --git a/tools/aapt2/SdkConstants.h b/tools/aapt2/SdkConstants.h
index e47704ea..f131cc6 100644
--- a/tools/aapt2/SdkConstants.h
+++ b/tools/aapt2/SdkConstants.h
@@ -60,6 +60,7 @@
SDK_S_V2 = 32,
SDK_TIRAMISU = 33,
SDK_UPSIDE_DOWN_CAKE = 34,
+ SDK_VANILLA_ICE_CREAM = 35,
SDK_CUR_DEVELOPMENT = 10000,
};
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt
index 803dc28..2f432cc 100644
--- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt
@@ -85,9 +85,13 @@
// Dump statistics, if specified.
options.statsFile.ifSet {
- PrintWriter(it).use { pw -> stats.dump(pw) }
+ PrintWriter(it).use { pw -> stats.dumpOverview(pw) }
log.i("Dump file created at $it")
}
+ options.apiListFile.ifSet {
+ PrintWriter(it).use { pw -> stats.dumpApis(pw) }
+ log.i("API list file created at $it")
+ }
}
/**
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt
index 9ff798a..e192516 100644
--- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt
@@ -110,6 +110,8 @@
var enableNonStubMethodCallDetection: SetOnce<Boolean> = SetOnce(false),
var statsFile: SetOnce<String?> = SetOnce(null),
+
+ var apiListFile: SetOnce<String?> = SetOnce(null),
) {
companion object {
@@ -255,6 +257,7 @@
"--debug-log" -> setLogFile(LogLevel.Debug, nextArg())
"--stats-file" -> ret.statsFile.setNextStringArg()
+ "--supported-api-list-file" -> ret.apiListFile.setNextStringArg()
else -> throw ArgumentsException("Unknown option: $arg")
}
@@ -392,6 +395,7 @@
enablePostTrace=$enablePostTrace,
enableNonStubMethodCallDetection=$enableNonStubMethodCallDetection,
statsFile=$statsFile,
+ apiListFile=$apiListFile,
}
""".trimIndent()
}
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenStats.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenStats.kt
index 50518e1..da61469 100644
--- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenStats.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenStats.kt
@@ -29,8 +29,25 @@
private val stats = mutableMapOf<String, Stats>()
- fun onVisitPolicyForMethod(fullClassName: String, methodName: String, descriptor: String,
- policy: FilterPolicyWithReason, access: Int) {
+ data class Api(
+ val fullClassName: String,
+ val methodName: String,
+ val methodDesc: String,
+ )
+
+ private val apis = mutableListOf<Api>()
+
+ fun onVisitPolicyForMethod(
+ fullClassName: String,
+ methodName: String,
+ descriptor: String,
+ policy: FilterPolicyWithReason,
+ access: Int
+ ) {
+ if (policy.policy.isSupported) {
+ apis.add(Api(fullClassName, methodName, descriptor))
+ }
+
// Ignore methods that aren't public
if ((access and Opcodes.ACC_PUBLIC) == 0) return
// Ignore methods that are abstract
@@ -39,7 +56,7 @@
if (policy.isIgnoredForStats) return
val packageName = resolvePackageName(fullClassName)
- val className = resolveClassName(fullClassName)
+ val className = resolveOuterClassName(fullClassName)
// Ignore methods for certain generated code
if (className.endsWith("Proto")
@@ -60,11 +77,11 @@
classStats.total += 1
}
- fun dump(pw: PrintWriter) {
+ fun dumpOverview(pw: PrintWriter) {
pw.printf("PackageName,ClassName,SupportedMethods,TotalMethods\n")
- stats.forEach { (packageName, packageStats) ->
+ stats.toSortedMap().forEach { (packageName, packageStats) ->
if (packageStats.supported > 0) {
- packageStats.children.forEach { (className, classStats) ->
+ packageStats.children.toSortedMap().forEach { (className, classStats) ->
pw.printf("%s,%s,%d,%d\n", packageName, className,
classStats.supported, classStats.total)
}
@@ -72,12 +89,26 @@
}
}
+ fun dumpApis(pw: PrintWriter) {
+ pw.printf("PackageName,ClassName,MethodName,MethodDesc\n")
+ apis.sortedWith(compareBy({ it.fullClassName }, { it.methodName }, { it.methodDesc }))
+ .forEach { api ->
+ pw.printf(
+ "%s,%s,%s,%s\n",
+ csvEscape(resolvePackageName(api.fullClassName)),
+ csvEscape(resolveClassName(api.fullClassName)),
+ csvEscape(api.methodName),
+ csvEscape(api.methodDesc),
+ )
+ }
+ }
+
private fun resolvePackageName(fullClassName: String): String {
val start = fullClassName.lastIndexOf('/')
return fullClassName.substring(0, start).toHumanReadableClassName()
}
- private fun resolveClassName(fullClassName: String): String {
+ private fun resolveOuterClassName(fullClassName: String): String {
val start = fullClassName.lastIndexOf('/')
val end = fullClassName.indexOf('$')
if (end == -1) {
@@ -86,4 +117,13 @@
return fullClassName.substring(start + 1, end)
}
}
+
+ private fun resolveClassName(fullClassName: String): String {
+ val pos = fullClassName.lastIndexOf('/')
+ if (pos == -1) {
+ return fullClassName
+ } else {
+ return fullClassName.substring(pos + 1)
+ }
+ }
}
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/Utils.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/Utils.kt
index aa63d8d9..10179ee 100644
--- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/Utils.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/Utils.kt
@@ -89,3 +89,10 @@
}
}
}
+
+/**
+ * Escape a string for a CSV field.
+ */
+fun csvEscape(value: String): String {
+ return "\"" + value.replace("\"", "\"\"") + "\""
+}