Merge changes I7907ba3c,I3e27690a,I860ee704,I02361fcd into main
* changes:
Elements overscrolling on other scene should not affect interruption
Always reset interruption deltas
Always use the transition scene(s) when computing element values
Correctly clear last placement values on nested elements
diff --git a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShimPriv_apk.asciipb b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShimPriv_apk.asciipb
index a40adac..82ef3e6 100644
--- a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShimPriv_apk.asciipb
+++ b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShimPriv_apk.asciipb
@@ -1,6 +1,6 @@
drops {
android_build_drop {
- build_id: "10093150"
+ build_id: "11947186"
target: "CtsShim"
source_file: "aosp_arm64/CtsShimPriv.apk"
}
@@ -8,7 +8,7 @@
version: ""
version_group: ""
git_project: "platform/frameworks/base"
- git_branch: "udc-dev"
+ git_branch: "main"
transform: TRANSFORM_NONE
transform_options {
}
diff --git a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShim_apk.asciipb b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShim_apk.asciipb
index 96444ba..7d0e5d7 100644
--- a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShim_apk.asciipb
+++ b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShim_apk.asciipb
@@ -1,6 +1,6 @@
drops {
android_build_drop {
- build_id: "10093150"
+ build_id: "11947186"
target: "CtsShim"
source_file: "aosp_arm64/CtsShim.apk"
}
@@ -8,7 +8,7 @@
version: ""
version_group: ""
git_project: "platform/frameworks/base"
- git_branch: "udc-dev"
+ git_branch: "main"
transform: TRANSFORM_NONE
transform_options {
}
diff --git a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShimPriv_apk.asciipb b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShimPriv_apk.asciipb
index 4d6f8ed..be32060 100644
--- a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShimPriv_apk.asciipb
+++ b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShimPriv_apk.asciipb
@@ -1,6 +1,6 @@
drops {
android_build_drop {
- build_id: "10093150"
+ build_id: "11947186"
target: "CtsShim"
source_file: "aosp_x86_64/CtsShimPriv.apk"
}
@@ -8,7 +8,7 @@
version: ""
version_group: ""
git_project: "platform/frameworks/base"
- git_branch: "udc-dev"
+ git_branch: "main"
transform: TRANSFORM_NONE
transform_options {
}
diff --git a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShim_apk.asciipb b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShim_apk.asciipb
index bfd6788..1a6448a 100644
--- a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShim_apk.asciipb
+++ b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShim_apk.asciipb
@@ -1,6 +1,6 @@
drops {
android_build_drop {
- build_id: "10093150"
+ build_id: "11947186"
target: "CtsShim"
source_file: "aosp_x86_64/CtsShim.apk"
}
@@ -8,7 +8,7 @@
version: ""
version_group: ""
git_project: "platform/frameworks/base"
- git_branch: "udc-dev"
+ git_branch: "main"
transform: TRANSFORM_NONE
transform_options {
}
diff --git a/Android.bp b/Android.bp
index af312bf..2becf07 100644
--- a/Android.bp
+++ b/Android.bp
@@ -404,6 +404,7 @@
"android.hardware.common.fmq-V1-java",
"bouncycastle-repackaged-unbundled",
"com.android.sysprop.foldlockbehavior",
+ "com.android.sysprop.view",
"framework-internal-utils",
// If MimeMap ever becomes its own APEX, then this dependency would need to be removed
// in favor of an API stubs dependency in java_library "framework" below.
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index e857175..c4ffa34 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -30,7 +30,7 @@
ktlint_hook = ${REPO_ROOT}/prebuilts/ktlint/ktlint.py --no-verify-format -f ${PREUPLOAD_FILES}
# This flag check hook runs only for "packages/SystemUI" subdirectory. If you want to include this check for other subdirectories, please modify flag_check.py.
-flag_hook = ${REPO_ROOT}/frameworks/base/packages/SystemUI/flag_check.py --msg=${PREUPLOAD_COMMIT_MESSAGE} --files=${PREUPLOAD_FILES} --project=${REPO_PATH}
+flag_hook = ${REPO_ROOT}/frameworks/base/packages/SystemUI/flag_check.py --msg=${PREUPLOAD_COMMIT_MESSAGE} --files=${PREUPLOAD_FILES} --project=${REPO_PROJECT}
[Tool Paths]
ktfmt = ${REPO_ROOT}/prebuilts/build-tools/common/framework/ktfmt.jar
diff --git a/cmds/bootanimation/Android.bp b/cmds/bootanimation/Android.bp
index 98767ee..3534624 100644
--- a/cmds/bootanimation/Android.bp
+++ b/cmds/bootanimation/Android.bp
@@ -74,7 +74,4 @@
"libGLESv2",
"libgui",
],
- whole_static_libs: [
- "libc++fs",
- ],
}
diff --git a/cmds/idmap2/Android.bp b/cmds/idmap2/Android.bp
index 6e51f00..58763a7 100644
--- a/cmds/idmap2/Android.bp
+++ b/cmds/idmap2/Android.bp
@@ -313,7 +313,6 @@
"libziparchive",
],
static_libs: [
- "libc++fs",
"libidmap2_policies",
"libidmap2_protos",
"libidmap2daidl",
diff --git a/core/api/current.txt b/core/api/current.txt
index a819b6e..bbb3932 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -5605,7 +5605,6 @@
method @Deprecated public void onCancel(android.content.DialogInterface);
method @Deprecated public android.app.Dialog onCreateDialog(android.os.Bundle);
method @Deprecated public void onDismiss(android.content.DialogInterface);
- method public android.view.LayoutInflater onGetLayoutInflater(android.os.Bundle);
method @Deprecated public void setCancelable(boolean);
method @Deprecated public void setShowsDialog(boolean);
method @Deprecated public void setStyle(int, int);
@@ -34056,6 +34055,7 @@
field public static final String DISALLOW_BLUETOOTH_SHARING = "no_bluetooth_sharing";
field public static final String DISALLOW_CAMERA_TOGGLE = "disallow_camera_toggle";
field public static final String DISALLOW_CELLULAR_2G = "no_cellular_2g";
+ field @FlaggedApi("android.nfc.enable_nfc_user_restriction") public static final String DISALLOW_CHANGE_NEAR_FIELD_COMMUNICATION_RADIO = "no_change_near_field_communication_radio";
field public static final String DISALLOW_CHANGE_WIFI_STATE = "no_change_wifi_state";
field public static final String DISALLOW_CONFIG_BLUETOOTH = "no_config_bluetooth";
field public static final String DISALLOW_CONFIG_BRIGHTNESS = "no_config_brightness";
diff --git a/core/java/android/app/AppOpsManagerInternal.java b/core/java/android/app/AppOpsManagerInternal.java
index f8a8f5d..b21defb 100644
--- a/core/java/android/app/AppOpsManagerInternal.java
+++ b/core/java/android/app/AppOpsManagerInternal.java
@@ -172,11 +172,9 @@
* @param virtualDeviceId the device for which to finish the op
* @param superImpl
*/
- default void finishOperation(IBinder clientId, int code, int uid, String packageName,
+ void finishOperation(IBinder clientId, int code, int uid, String packageName,
String attributionTag, int virtualDeviceId, @NonNull HexConsumer<IBinder, Integer,
- Integer, String, String, Integer> superImpl) {
- superImpl.accept(clientId, code, uid, packageName, attributionTag, virtualDeviceId);
- }
+ Integer, String, String, Integer> superImpl);
/**
* Allows overriding finish proxy op.
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index ffb920b..15b13dc 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -757,15 +757,6 @@
void addStartInfoTimestamp(int key, long timestampNs, int userId);
/**
- * Reports view related timestamps to be added to the calling apps most
- * recent {@link ApplicationStartInfo}.
- *
- * @param renderThreadDrawStartTimeNs Clock monotonic time in nanoseconds of RenderThread draw start
- * @param framePresentedTimeNs Clock monotonic time in nanoseconds of frame presented
- */
- oneway void reportStartInfoViewTimestamps(long renderThreadDrawStartTimeNs, long framePresentedTimeNs);
-
- /**
* Return a list of {@link ApplicationExitInfo} records.
*
* <p class="note"> Note: System stores these historical information in a ring buffer, older
diff --git a/core/java/android/app/notification.aconfig b/core/java/android/app/notification.aconfig
index 2d78317..73ac263 100644
--- a/core/java/android/app/notification.aconfig
+++ b/core/java/android/app/notification.aconfig
@@ -199,3 +199,11 @@
description: "redacts notifications on the lockscreen if they have the 'sensitiveContent' flag"
bug: "343631648"
}
+
+flag {
+ name: "api_rich_ongoing"
+ is_exported: true
+ namespace: "systemui"
+ description: "Guards new android.app.richongoingnotification api"
+ bug: "337261753"
+}
\ No newline at end of file
diff --git a/core/java/android/app/wearable/WearableSensingManager.java b/core/java/android/app/wearable/WearableSensingManager.java
index b2b14ce..d28969d 100644
--- a/core/java/android/app/wearable/WearableSensingManager.java
+++ b/core/java/android/app/wearable/WearableSensingManager.java
@@ -449,7 +449,7 @@
* Consumer<android.service.voice.HotwordAudioStream>}, the system will check whether the {@link
* android.service.voice.VoiceInteractionService} at that time is {@code
* targetVisComponentName}. If not, the system will call {@link
- * WearableSensingService#onActiveHotwordAudioStopRequested()} and will not forward the audio
+ * WearableSensingService#onStopHotwordAudioStream()} and will not forward the audio
* data to the current {@link android.service.voice.HotwordDetectionService} nor {@link
* android.service.voice.VoiceInteractionService}. The system will not send a status code to
* {@code statusConsumer} regarding the {@code targetVisComponentName} check. The caller is
@@ -464,9 +464,9 @@
* continue to use the previous consumers after receiving a new one.
*
* <p>If the {@code statusConsumer} returns {@link STATUS_SUCCESS}, the caller should call
- * {@link #stopListeningForHotword(Executor, Consumer)} when it wants the wearable to stop
+ * {@link #stopHotwordRecognition(Executor, Consumer)} when it wants the wearable to stop
* listening for hotword. If the {@code statusConsumer} returns any other status code, a failure
- * has occurred and calling {@link #stopListeningForHotword(Executor, Consumer)} is not
+ * has occurred and calling {@link #stopHotwordRecognition(Executor, Consumer)} is not
* required. The system will not retry listening automatically. The caller should call this
* method again if they want to retry.
*
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index 6168b68..93cc71b 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -695,13 +695,13 @@
* <p>If the caller is running on a managed profile, it'll return only the current profile.
* Otherwise it'll return the same list as {@link UserManager#getUserProfiles()} would.
*
- * <p>To get hidden profile {@link UserManager.USER_TYPE_PROFILE_PRIVATE},
+ * <p>To get hidden profile {@link UserManager#USER_TYPE_PROFILE_PRIVATE},
* caller should have either:</p>
* <ul>
- * <li>the privileged {@link android.Manifest.permission.ACCESS_HIDDEN_PROFILES_FULL}
+ * <li>the privileged {@code android.Manifest.permission#ACCESS_HIDDEN_PROFILES_FULL}
* permission</li>
- * <li>the normal {@link android.Manifest.permission.ACCESS_HIDDEN_PROFILES} permission and the
- * {@link android.app.role.RoleManager.ROLE_HOME} role. </li>
+ * <li>the normal {@link android.Manifest.permission#ACCESS_HIDDEN_PROFILES} permission and the
+ * {@link android.app.role.RoleManager#ROLE_HOME} role. </li>
* </ul>
*/
@SuppressLint("RequiresPermission")
@@ -764,13 +764,13 @@
* list.</li>
* </ul>
*
- * <p>If the user in question is a hidden profile {@link UserManager.USER_TYPE_PROFILE_PRIVATE},
+ * <p>If the user in question is a hidden profile {@link UserManager#USER_TYPE_PROFILE_PRIVATE},
* caller should have either:</p>
* <ul>
- * <li>the privileged {@link android.Manifest.permission.ACCESS_HIDDEN_PROFILES_FULL}
+ * <li>the privileged {@code android.Manifest.permission#ACCESS_HIDDEN_PROFILES_FULL}
* permission</li>
- * <li>the normal {@link android.Manifest.permission.ACCESS_HIDDEN_PROFILES} permission and the
- * {@link android.app.role.RoleManager.ROLE_HOME} role. </li>
+ * <li>the normal {@link android.Manifest.permission#ACCESS_HIDDEN_PROFILES} permission and the
+ * {@link android.app.role.RoleManager#ROLE_HOME} role. </li>
* </ul>
*
* @param packageName The specific package to query. If null, it checks all installed packages
@@ -820,13 +820,13 @@
* Returns information related to a user which is useful for displaying UI elements
* to distinguish it from other users (eg, badges).
*
- * <p>If the user in question is a hidden profile {@link UserManager.USER_TYPE_PROFILE_PRIVATE},
+ * <p>If the user in question is a hidden profile {@link UserManager#USER_TYPE_PROFILE_PRIVATE},
* caller should have either:</p>
* <ul>
- * <li>the privileged {@link android.Manifest.permission.ACCESS_HIDDEN_PROFILES_FULL}
+ * <li>the privileged {@code android.Manifest.permission#ACCESS_HIDDEN_PROFILES_FULL}
* permission</li>
- * <li>the normal {@link android.Manifest.permission.ACCESS_HIDDEN_PROFILES} permission and the
- * {@link android.app.role.RoleManager.ROLE_HOME} role. </li>
+ * <li>the normal {@link android.Manifest.permission#ACCESS_HIDDEN_PROFILES} permission and the
+ * {@link android.app.role.RoleManager#ROLE_HOME} role. </li>
* </ul>
*
* @param userHandle user handle of the user for which LauncherUserInfo is requested.
@@ -873,13 +873,13 @@
* </ul>
* </p>
*
- * <p>If the user in question is a hidden profile {@link UserManager.USER_TYPE_PROFILE_PRIVATE},
+ * <p>If the user in question is a hidden profile {@link UserManager#USER_TYPE_PROFILE_PRIVATE},
* caller should have either:</p>
* <ul>
- * <li>the privileged {@link android.Manifest.permission.ACCESS_HIDDEN_PROFILES_FULL}
+ * <li>the privileged {@code android.Manifest.permission#ACCESS_HIDDEN_PROFILES_FULL}
* permission</li>
- * <li>the normal {@link android.Manifest.permission.ACCESS_HIDDEN_PROFILES} permission and the
- * {@link android.app.role.RoleManager.ROLE_HOME} role. </li>
+ * <li>the normal {@link android.Manifest.permission#ACCESS_HIDDEN_PROFILES} permission and the
+ * {@link android.app.role.RoleManager#ROLE_HOME} role. </li>
* </ul>
*
* @param packageName the package for which intent sender to launch App Market Activity is
@@ -913,13 +913,13 @@
* <p>An empty list denotes that all system packages should be treated as pre-installed for that
* user at creation.
*
- * <p>If the user in question is a hidden profile {@link UserManager.USER_TYPE_PROFILE_PRIVATE},
+ * <p>If the user in question is a hidden profile {@link UserManager#USER_TYPE_PROFILE_PRIVATE},
* caller should have either:</p>
* <ul>
- * <li>the privileged {@link android.Manifest.permission.ACCESS_HIDDEN_PROFILES_FULL}
+ * <li>the privileged {@code android.Manifest.permission#ACCESS_HIDDEN_PROFILES_FULL}
* permission</li>
- * <li>the normal {@link android.Manifest.permission.ACCESS_HIDDEN_PROFILES} permission and the
- * {@link android.app.role.RoleManager.ROLE_HOME} role. </li>
+ * <li>the normal {@link android.Manifest.permission#ACCESS_HIDDEN_PROFILES} permission and the
+ * {@link android.app.role.RoleManager#ROLE_HOME} role. </li>
* </ul>
*
* @param userHandle the user for which installed system packages are required.
@@ -945,7 +945,7 @@
/**
* Returns {@link IntentSender} which can be used to start the Private Space Settings Activity.
*
- * <p> Caller should have {@link android.app.role.RoleManager.ROLE_HOME} and either of the
+ * <p> Caller should have {@link android.app.role.RoleManager#ROLE_HOME} and either of the
* permissions required.</p>
*
* @return {@link IntentSender} object which launches the Private Space Settings Activity, if
@@ -968,13 +968,13 @@
* Returns the activity info for a given intent and user handle, if it resolves. Otherwise it
* returns null.
*
- * <p>If the user in question is a hidden profile {@link UserManager.USER_TYPE_PROFILE_PRIVATE},
+ * <p>If the user in question is a hidden profile {@link UserManager#USER_TYPE_PROFILE_PRIVATE},
* caller should have either:</p>
* <ul>
- * <li>the privileged {@link android.Manifest.permission.ACCESS_HIDDEN_PROFILES_FULL}
+ * <li>the privileged {@code android.Manifest.permission#ACCESS_HIDDEN_PROFILES_FULL}
* permission</li>
- * <li>the normal {@link android.Manifest.permission.ACCESS_HIDDEN_PROFILES} permission and the
- * {@link android.app.role.RoleManager.ROLE_HOME} role. </li>
+ * <li>the normal {@link android.Manifest.permission#ACCESS_HIDDEN_PROFILES} permission and the
+ * {@link android.app.role.RoleManager#ROLE_HOME} role. </li>
* </ul>
*
* @param intent The intent to find a match for.
@@ -1033,13 +1033,13 @@
/**
* Starts a Main activity in the specified profile.
*
- * <p>If the user in question is a hidden profile {@link UserManager.USER_TYPE_PROFILE_PRIVATE},
+ * <p>If the user in question is a hidden profile {@link UserManager#USER_TYPE_PROFILE_PRIVATE},
* caller should have either:</p>
* <ul>
- * <li>the privileged {@link android.Manifest.permission.ACCESS_HIDDEN_PROFILES_FULL}
+ * <li>the privileged {@code android.Manifest.permission#ACCESS_HIDDEN_PROFILES_FULL}
* permission</li>
- * <li>the normal {@link android.Manifest.permission.ACCESS_HIDDEN_PROFILES} permission and the
- * {@link android.app.role.RoleManager.ROLE_HOME} role. </li>
+ * <li>the normal {@link android.Manifest.permission#ACCESS_HIDDEN_PROFILES} permission and the
+ * {@link android.app.role.RoleManager#ROLE_HOME} role. </li>
* </ul>
*
* @param component The ComponentName of the activity to launch
@@ -1087,13 +1087,13 @@
* Starts the settings activity to show the application details for a
* package in the specified profile.
*
- * <p>If the user in question is a hidden profile {@link UserManager.USER_TYPE_PROFILE_PRIVATE},
+ * <p>If the user in question is a hidden profile {@link UserManager#USER_TYPE_PROFILE_PRIVATE},
* caller should have either:</p>
* <ul>
- * <li>the privileged {@link android.Manifest.permission.ACCESS_HIDDEN_PROFILES_FULL}
+ * <li>the privileged {@code android.Manifest.permission#ACCESS_HIDDEN_PROFILES_FULL}
* permission</li>
- * <li>the normal {@link android.Manifest.permission.ACCESS_HIDDEN_PROFILES} permission and the
- * {@link android.app.role.RoleManager.ROLE_HOME} role. </li>
+ * <li>the normal {@link android.Manifest.permission#ACCESS_HIDDEN_PROFILES} permission and the
+ * {@link android.app.role.RoleManager#ROLE_HOME} role. </li>
* </ul>
*
* @param component The ComponentName of the package to launch settings for.
@@ -1215,13 +1215,13 @@
/**
* Checks if the package is installed and enabled for a profile.
*
- * <p>If the user in question is a hidden profile {@link UserManager.USER_TYPE_PROFILE_PRIVATE},
+ * <p>If the user in question is a hidden profile {@link UserManager#USER_TYPE_PROFILE_PRIVATE},
* caller should have either:</p>
* <ul>
- * <li>the privileged {@link android.Manifest.permission.ACCESS_HIDDEN_PROFILES_FULL}
+ * <li>the privileged {@code android.Manifest.permission#ACCESS_HIDDEN_PROFILES_FULL}
* permission</li>
- * <li>the normal {@link android.Manifest.permission.ACCESS_HIDDEN_PROFILES} permission and the
- * {@link android.app.role.RoleManager.ROLE_HOME} role. </li>
+ * <li>the normal {@link android.Manifest.permission#ACCESS_HIDDEN_PROFILES} permission and the
+ * {@link android.app.role.RoleManager#ROLE_HOME} role. </li>
* </ul>
*
* @param packageName The package to check.
@@ -1249,13 +1249,13 @@
* <p>The contents of this {@link Bundle} are supposed to be a contract between the suspending
* app and the launcher.
*
- * <p>If the user in question is a hidden profile {@link UserManager.USER_TYPE_PROFILE_PRIVATE},
+ * <p>If the user in question is a hidden profile {@link UserManager#USER_TYPE_PROFILE_PRIVATE},
* caller should have either:</p>
* <ul>
- * <li>the privileged {@link android.Manifest.permission.ACCESS_HIDDEN_PROFILES_FULL}
+ * <li>the privileged {@code android.Manifest.permission#ACCESS_HIDDEN_PROFILES_FULL}
* permission</li>
- * <li>the normal {@link android.Manifest.permission.ACCESS_HIDDEN_PROFILES} permission and the
- * {@link android.app.role.RoleManager.ROLE_HOME} role. </li>
+ * <li>the normal {@link android.Manifest.permission#ACCESS_HIDDEN_PROFILES} permission and the
+ * {@link android.app.role.RoleManager#ROLE_HOME} role. </li>
* </ul>
*
* <p>Note: This just returns whatever extras were provided to the system, <em>which might
@@ -1286,13 +1286,13 @@
* could be done because the package was marked as distracting to the user via
* {@code PackageManager.setDistractingPackageRestrictions(String[], int)}.
*
- * <p>If the user in question is a hidden profile {@link UserManager.USER_TYPE_PROFILE_PRIVATE},
+ * <p>If the user in question is a hidden profile {@link UserManager#USER_TYPE_PROFILE_PRIVATE},
* caller should have either:</p>
* <ul>
- * <li>the privileged {@link android.Manifest.permission.ACCESS_HIDDEN_PROFILES_FULL}
+ * <li>the privileged {@code android.Manifest.permission#ACCESS_HIDDEN_PROFILES_FULL}
* permission</li>
- * <li>the normal {@link android.Manifest.permission.ACCESS_HIDDEN_PROFILES} permission and the
- * {@link android.app.role.RoleManager.ROLE_HOME} role. </li>
+ * <li>the normal {@link android.Manifest.permission#ACCESS_HIDDEN_PROFILES} permission and the
+ * {@link android.app.role.RoleManager#ROLE_HOME} role. </li>
* </ul>
*
* @param packageName The package for which to check.
@@ -1316,13 +1316,13 @@
/**
* Returns {@link ApplicationInfo} about an application installed for a specific user profile.
*
- * <p>If the user in question is a hidden profile {@link UserManager.USER_TYPE_PROFILE_PRIVATE},
+ * <p>If the user in question is a hidden profile {@link UserManager#USER_TYPE_PROFILE_PRIVATE},
* caller should have either:</p>
* <ul>
- * <li>the privileged {@link android.Manifest.permission.ACCESS_HIDDEN_PROFILES_FULL}
+ * <li>the privileged {@code android.Manifest.permission#ACCESS_HIDDEN_PROFILES_FULL}
* permission</li>
- * <li>the normal {@link android.Manifest.permission.ACCESS_HIDDEN_PROFILES} permission and the
- * {@link android.app.role.RoleManager.ROLE_HOME} role. </li>
+ * <li>the normal {@link android.Manifest.permission#ACCESS_HIDDEN_PROFILES} permission and the
+ * {@link android.app.role.RoleManager#ROLE_HOME} role. </li>
* </ul>
*
* @param packageName The package name of the application
@@ -1385,13 +1385,13 @@
* <p>The activity may still not be exported, in which case {@link #startMainActivity} will
* throw a {@link SecurityException} unless the caller has the same UID as the target app's.
*
- * <p>If the user in question is a hidden profile {@link UserManager.USER_TYPE_PROFILE_PRIVATE},
+ * <p>If the user in question is a hidden profile {@link UserManager#USER_TYPE_PROFILE_PRIVATE},
* caller should have either:</p>
* <ul>
- * <li>the privileged {@link android.Manifest.permission.ACCESS_HIDDEN_PROFILES_FULL}
+ * <li>the privileged {@code android.Manifest.permission#ACCESS_HIDDEN_PROFILES_FULL}
* permission</li>
- * <li>the normal {@link android.Manifest.permission.ACCESS_HIDDEN_PROFILES} permission and the
- * {@link android.app.role.RoleManager.ROLE_HOME} role. </li>
+ * <li>the normal {@link android.Manifest.permission#ACCESS_HIDDEN_PROFILES} permission and the
+ * {@link android.app.role.RoleManager#ROLE_HOME} role. </li>
* </ul>
*
* @param component The activity to check.
@@ -1960,13 +1960,13 @@
/**
* Registers a callback for changes to packages in this user and managed profiles.
*
- * <p>To receive callbacks for hidden profile {@link UserManager.USER_TYPE_PROFILE_PRIVATE},
+ * <p>To receive callbacks for hidden profile {@link UserManager#USER_TYPE_PROFILE_PRIVATE},
* caller should have either:</p>
* <ul>
- * <li>the privileged {@link android.Manifest.permission.ACCESS_HIDDEN_PROFILES_FULL}
+ * <li>the privileged {@code android.Manifest.permission#ACCESS_HIDDEN_PROFILES_FULL}
* permission</li>
- * <li>the normal {@link android.Manifest.permission.ACCESS_HIDDEN_PROFILES} permission and the
- * {@link android.app.role.RoleManager.ROLE_HOME} role. </li>
+ * <li>the normal {@link android.Manifest.permission#ACCESS_HIDDEN_PROFILES} permission and the
+ * {@link android.app.role.RoleManager#ROLE_HOME} role. </li>
* </ul>
*
* @param callback The callback to register.
@@ -1981,13 +1981,13 @@
/**
* Registers a callback for changes to packages in this user and managed profiles.
*
- * <p>To receive callbacks for hidden profile {@link UserManager.USER_TYPE_PROFILE_PRIVATE},
+ * <p>To receive callbacks for hidden profile {@link UserManager#USER_TYPE_PROFILE_PRIVATE},
* caller should have either:</p>
* <ul>
- * <li>the privileged {@link android.Manifest.permission.ACCESS_HIDDEN_PROFILES_FULL}
+ * <li>the privileged {@code android.Manifest.permission#ACCESS_HIDDEN_PROFILES_FULL}
* permission</li>
- * <li>the normal {@link android.Manifest.permission.ACCESS_HIDDEN_PROFILES} permission and the
- * {@link android.app.role.RoleManager.ROLE_HOME} role. </li>
+ * <li>the normal {@link android.Manifest.permission#ACCESS_HIDDEN_PROFILES} permission and the
+ * {@link android.app.role.RoleManager#ROLE_HOME} role. </li>
* </ul>
*
* @param callback The callback to register.
@@ -2446,13 +2446,13 @@
* package name in the app's manifest, have the android.permission.QUERY_ALL_PACKAGES, or be
* the session owner to retrieve these details.
*
- * <p>To receive callbacks for hidden profile {@link UserManager.USER_TYPE_PROFILE_PRIVATE},
+ * <p>To receive callbacks for hidden profile {@link UserManager#USER_TYPE_PROFILE_PRIVATE},
* caller should have either:</p>
* <ul>
- * <li>the privileged {@link android.Manifest.permission.ACCESS_HIDDEN_PROFILES}
+ * <li>the privileged {@code android.Manifest.permission#ACCESS_HIDDEN_PROFILES_FULL}
* permission</li>
- * <li>the normal {@link android.Manifest.permission.ACCESS_HIDDEN_PROFILES} permission and the
- * {@link android.app.role.RoleManager.ROLE_HOME} role. </li>
+ * <li>the normal {@link android.Manifest.permission#ACCESS_HIDDEN_PROFILES} permission and the
+ * {@link android.app.role.RoleManager#ROLE_HOME} role. </li>
* </ul>
*
* @see PackageInstaller#getAllSessions()
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 821034a..c673d58 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -2797,6 +2797,8 @@
public int developmentInstallFlags = 0;
/** {@hide} */
public int unarchiveId = -1;
+ /** {@hide} */
+ public @Nullable String dexoptCompilerFilter = null;
private final ArrayMap<String, Integer> mPermissionStates;
@@ -2850,6 +2852,7 @@
applicationEnabledSettingPersistent = source.readBoolean();
developmentInstallFlags = source.readInt();
unarchiveId = source.readInt();
+ dexoptCompilerFilter = source.readString();
}
/** {@hide} */
@@ -2885,6 +2888,7 @@
ret.applicationEnabledSettingPersistent = applicationEnabledSettingPersistent;
ret.developmentInstallFlags = developmentInstallFlags;
ret.unarchiveId = unarchiveId;
+ ret.dexoptCompilerFilter = dexoptCompilerFilter;
return ret;
}
@@ -3564,6 +3568,11 @@
}
/** @hide */
+ public void setDexoptCompilerFilter(@Nullable String dexoptCompilerFilter) {
+ this.dexoptCompilerFilter = dexoptCompilerFilter;
+ }
+
+ /** @hide */
@NonNull
public ArrayMap<String, Integer> getPermissionStates() {
return mPermissionStates;
@@ -3622,6 +3631,7 @@
applicationEnabledSettingPersistent);
pw.printHexPair("developmentInstallFlags", developmentInstallFlags);
pw.printPair("unarchiveId", unarchiveId);
+ pw.printPair("dexoptCompilerFilter", dexoptCompilerFilter);
pw.println();
}
@@ -3667,6 +3677,7 @@
dest.writeBoolean(applicationEnabledSettingPersistent);
dest.writeInt(developmentInstallFlags);
dest.writeInt(unarchiveId);
+ dest.writeString(dexoptCompilerFilter);
}
public static final Parcelable.Creator<SessionParams>
diff --git a/core/java/android/database/DefaultDatabaseErrorHandler.java b/core/java/android/database/DefaultDatabaseErrorHandler.java
old mode 100755
new mode 100644
diff --git a/core/java/android/hardware/biometrics/BiometricPrompt.java b/core/java/android/hardware/biometrics/BiometricPrompt.java
index 61f1ee1..e2159f7 100644
--- a/core/java/android/hardware/biometrics/BiometricPrompt.java
+++ b/core/java/android/hardware/biometrics/BiometricPrompt.java
@@ -38,6 +38,9 @@
import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
import android.hardware.face.FaceManager;
import android.hardware.fingerprint.FingerprintManager;
import android.os.Binder;
@@ -193,7 +196,11 @@
@RequiresPermission(SET_BIOMETRIC_DIALOG_ADVANCED)
@NonNull
public BiometricPrompt.Builder setLogoRes(@DrawableRes int logoRes) {
- mPromptInfo.setLogoRes(logoRes);
+ if (mPromptInfo.getLogoBitmap() != null) {
+ throw new IllegalStateException(
+ "Exclusively one of logo resource or logo bitmap can be set");
+ }
+ mPromptInfo.setLogo(logoRes, convertDrawableToBitmap(mContext.getDrawable(logoRes)));
return this;
}
@@ -212,7 +219,11 @@
@RequiresPermission(SET_BIOMETRIC_DIALOG_ADVANCED)
@NonNull
public BiometricPrompt.Builder setLogoBitmap(@NonNull Bitmap logoBitmap) {
- mPromptInfo.setLogoBitmap(logoBitmap);
+ if (mPromptInfo.getLogoRes() != -1) {
+ throw new IllegalStateException(
+ "Exclusively one of logo resource or logo bitmap can be set");
+ }
+ mPromptInfo.setLogo(-1, logoBitmap);
return this;
}
@@ -1516,4 +1527,29 @@
private static boolean isCredentialAllowed(@Authenticators.Types int allowedAuthenticators) {
return (allowedAuthenticators & Authenticators.DEVICE_CREDENTIAL) != 0;
}
+
+ /** Converts {@code drawable} to a {@link Bitmap}. */
+ private static Bitmap convertDrawableToBitmap(Drawable drawable) {
+ if (drawable == null) {
+ return null;
+ }
+
+ if (drawable instanceof BitmapDrawable) {
+ return ((BitmapDrawable) drawable).getBitmap();
+ }
+
+ Bitmap bitmap;
+ if (drawable.getIntrinsicWidth() <= 0 || drawable.getIntrinsicHeight() <= 0) {
+ bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
+ // Single color bitmap will be created of 1x1 pixel
+ } else {
+ bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(),
+ drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
+ }
+
+ final Canvas canvas = new Canvas(bitmap);
+ drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
+ drawable.draw(canvas);
+ return bitmap;
+ }
}
diff --git a/core/java/android/hardware/biometrics/PromptInfo.java b/core/java/android/hardware/biometrics/PromptInfo.java
index bb07b9b..f4a3c87 100644
--- a/core/java/android/hardware/biometrics/PromptInfo.java
+++ b/core/java/android/hardware/biometrics/PromptInfo.java
@@ -217,14 +217,17 @@
// LINT.ThenChange(frameworks/base/core/java/android/hardware/biometrics/BiometricPrompt.java)
// Setters
- public void setLogoRes(@DrawableRes int logoRes) {
- mLogoRes = logoRes;
- checkOnlyOneLogoSet();
- }
- public void setLogoBitmap(@NonNull Bitmap logoBitmap) {
+ /**
+ * Sets logo res and bitmap
+ *
+ * @param logoRes The logo res set by the app; Or -1 if the app sets bitmap directly.
+ * @param logoBitmap The bitmap from logoRes if the app sets logoRes; Or the bitmap set by the
+ * app directly.
+ */
+ public void setLogo(@DrawableRes int logoRes, @NonNull Bitmap logoBitmap) {
+ mLogoRes = logoRes;
mLogoBitmap = logoBitmap;
- checkOnlyOneLogoSet();
}
public void setLogoDescription(@NonNull String logoDescription) {
@@ -326,13 +329,29 @@
}
// Getters
+
+ /**
+ * Returns the logo bitmap either from logo resource or bitmap passed in from the app.
+ */
+ public Bitmap getLogo() {
+ return mLogoBitmap;
+ }
+
+ /**
+ * Returns the logo res set by the app.
+ */
@DrawableRes
public int getLogoRes() {
return mLogoRes;
}
+ /**
+ * Returns the logo bitmap set by the app.
+ */
public Bitmap getLogoBitmap() {
- return mLogoBitmap;
+ // If mLogoRes has been set, return null since mLogoBitmap is from the res, but not from
+ // the app directly.
+ return mLogoRes == -1 ? mLogoBitmap : null;
}
public String getLogoDescription() {
@@ -436,10 +455,4 @@
return mComponentNameForConfirmDeviceCredentialActivity;
}
- private void checkOnlyOneLogoSet() {
- if (mLogoRes != -1 && mLogoBitmap != null) {
- throw new IllegalStateException(
- "Exclusively one of logo resource or logo bitmap can be set");
- }
- }
}
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index de26384..4819f67 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -2360,11 +2360,8 @@
* <p>If the session configuration is not supported, the AE mode reported in the
* CaptureResult will be 'ON' instead of 'ON_LOW_LIGHT_BOOST_BRIGHTNESS_PRIORITY'.</p>
* <p>When this AE mode is enabled, the CaptureResult field
- * {@link CaptureResult#CONTROL_LOW_LIGHT_BOOST_STATE android.control.lowLightBoostState} will be present and not null. Otherwise, the
- * {@link CaptureResult#CONTROL_LOW_LIGHT_BOOST_STATE android.control.lowLightBoostState} field will not be present in the CaptureResult.</p>
- * <p>The application can observe the CaptureResult field
- * {@link CaptureResult#CONTROL_LOW_LIGHT_BOOST_STATE android.control.lowLightBoostState} to determine when low light boost is 'ACTIVE' or
- * 'INACTIVE'.</p>
+ * {@link CaptureResult#CONTROL_LOW_LIGHT_BOOST_STATE android.control.lowLightBoostState} will indicate when low light boost is 'ACTIVE'
+ * or 'INACTIVE'. By default {@link CaptureResult#CONTROL_LOW_LIGHT_BOOST_STATE android.control.lowLightBoostState} will be 'INACTIVE'.</p>
* <p>The low light boost is 'ACTIVE' once the scene lighting condition is less than the
* upper bound lux value defined by {@link CameraCharacteristics#CONTROL_LOW_LIGHT_BOOST_INFO_LUMINANCE_RANGE android.control.lowLightBoostInfoLuminanceRange}.
* This mode will be 'INACTIVE' once the scene lighting condition is greater than the
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index ef83f9a..d652b4c 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -2819,12 +2819,11 @@
* <p>When low light boost is enabled by setting the AE mode to
* 'ON_LOW_LIGHT_BOOST_BRIGHTNESS_PRIORITY', it can dynamically apply a low light
* boost when the light level threshold is exceeded.</p>
- * <p>This field is present in the CaptureResult when the AE mode is set to
- * 'ON_LOW_LIGHT_BOOST_BRIGHTNESS_PRIORITY'. Otherwise, the field is not present.</p>
* <p>This state indicates when low light boost is 'ACTIVE' and applied. Similarly, it can
* indicate when it is not being applied by returning 'INACTIVE'.</p>
* <p>This key will be absent from the CaptureResult if AE mode is not set to
* 'ON_LOW_LIGHT_BOOST_BRIGHTNESS_PRIORITY.</p>
+ * <p>The default value will always be 'INACTIVE'.</p>
* <p><b>Possible values:</b></p>
* <ul>
* <li>{@link #CONTROL_LOW_LIGHT_BOOST_STATE_INACTIVE INACTIVE}</li>
diff --git a/core/java/android/hardware/camera2/params/OutputConfiguration.java b/core/java/android/hardware/camera2/params/OutputConfiguration.java
index dda52dd..ebcc371 100644
--- a/core/java/android/hardware/camera2/params/OutputConfiguration.java
+++ b/core/java/android/hardware/camera2/params/OutputConfiguration.java
@@ -638,13 +638,15 @@
/**
* Create a list of {@link OutputConfiguration} instances for a
- * {@link android.hardware.camera2.params.MultiResolutionImageReader}.
+ * {@link MultiResolutionImageReader}.
*
* <p>This method can be used to create query OutputConfigurations for a
* MultiResolutionImageReader that can be included in a SessionConfiguration passed into
- * {@link CameraDeviceSetup#isSessionConfigurationSupported} before opening and setting up
- * a camera device in full, at which point {@link #setSurfacesForMultiResolutionOutput}
- * can be used to link to the actual MultiResolutionImageReader.</p>
+ * {@link
+ * android.hardware.camera2.CameraDevice.CameraDeviceSetup#isSessionConfigurationSupported}
+ * before opening and setting up a camera device in full, at which point {@link
+ * #setSurfacesForMultiResolutionOutput} can be used to link to the actual
+ * MultiResolutionImageReader.</p>
*
* <p>This constructor takes same arguments used to create a {@link
* MultiResolutionImageReader}: a collection of {@link MultiResolutionStreamInfo}
@@ -655,12 +657,12 @@
* @param format The format of the MultiResolutionImageReader. This must be one of the {@link
* android.graphics.ImageFormat} or {@link android.graphics.PixelFormat} constants
* supported by the camera device. Note that not all formats are supported, like
- * {@link ImageFormat.NV21}. The supported multi-resolution reader format can be
+ * {@link ImageFormat#NV21}. The supported multi-resolution reader format can be
* queried by {@link MultiResolutionStreamConfigurationMap#getOutputFormats}.
*
* @return The list of {@link OutputConfiguration} objects for a MultiResolutionImageReader.
*
- * @throws IllegaArgumentException If the {@code streams} is null or doesn't contain
+ * @throws IllegalArgumentException If the {@code streams} is null or doesn't contain
* at least 2 items, or if {@code format} isn't a valid camera
* format.
*
@@ -710,7 +712,7 @@
* instances.</p>
*
* @param outputConfigurations The OutputConfiguration objects created by {@link
- * #createInstancesFromMultiResolutionOutput}
+ * #createInstancesForMultiResolutionOutput}
* @param multiResolutionImageReader The MultiResolutionImageReader object created from the same
* MultiResolutionStreamInfo parameters as
* {@code outputConfigurations}.
@@ -759,31 +761,33 @@
* the deferred Surface can be obtained: (1) from {@link android.view.SurfaceView}
* by calling {@link android.view.SurfaceHolder#getSurface}, (2) from
* {@link android.graphics.SurfaceTexture} via
- * {@link android.view.Surface#Surface(android.graphics.SurfaceTexture)}, (3) from {@link
- * android.media.MediaRecorder} via {@link android.media.MediaRecorder.getSurface} or {@link
- * android.media.MediaCodec#createPersistentInputSurface}, or (4) from {@link
- * android.media.MediaCodce} via {@link android.media.MediaCodec#createInputSurface} or {@link
- * android.media.MediaCodec#createPersistentInputSource}.</p>
+ * {@link android.view.Surface#Surface(android.graphics.SurfaceTexture)}, (3) from
+ * {@link android.media.MediaRecorder} via {@link android.media.MediaRecorder#getSurface} or
+ * {@link android.media.MediaCodec#createPersistentInputSurface}, or (4) from
+ * {@link android.media.MediaCodec} via {@link android.media.MediaCodec#createInputSurface} or
+ * {@link android.media.MediaCodec#createPersistentInputSurface}.</p>
*
* <ul>
* <li>Surfaces for {@link android.view.SurfaceView} and {@link android.graphics.SurfaceTexture}
* can be deferred until after {@link CameraDevice#createCaptureSession}. In that case, the
* output Surface must be set via {@link #addSurface}, and the Surface configuration must be
- * finalized via {@link CameraCaptureSession#finalizeOutputConfiguration} before submitting
+ * finalized via {@link CameraCaptureSession#finalizeOutputConfigurations} before submitting
* a request with the Surface target.</li>
* <li>For all other target types, the output Surface must be set by {@link #addSurface},
- * and {@link CameraCaptureSession#finalizeOutputConfiguration} is not needed because the
+ * and {@link CameraCaptureSession#finalizeOutputConfigurations} is not needed because the
* OutputConfiguration used to create the session will contain the actual Surface.</li>
* </ul>
*
* <p>Before {@link android.os.Build.VERSION_CODES#VANILLA_ICE_CREAM Android V}, only {@link
* android.view.SurfaceView} and {@link android.graphics.SurfaceTexture} are supported. Both
* kind of outputs can be deferred until after {@link
- * CameraDevice#createCaptureSessionByOutputConfiguration}.</p>
+ * CameraDevice#createCaptureSessionByOutputConfigurations}.</p>
*
* <p>An OutputConfiguration object created by this constructor can be used for {@link
- * CameraDeviceSetup.isSessionConfigurationSupported} and {@link
- * CameraDeviceSetup.getSessionCharacteristics} without having called {@link #addSurface}.</p>
+ * android.hardware.camera2.CameraDevice.CameraDeviceSetup#isSessionConfigurationSupported}
+ * and {@link
+ * android.hardware.camera2.CameraDevice.CameraDeviceSetup#getSessionCharacteristics} without
+ * having called {@link #addSurface}.</p>
*
* @param surfaceSize Size for the deferred surface.
* @param klass a non-{@code null} {@link Class} object reference that indicates the source of
@@ -849,8 +853,10 @@
* before creating the capture session.</p>
*
* <p>An OutputConfiguration object created by this constructor can be used for {@link
- * CameraDeviceSetup.isSessionConfigurationSupported} and {@link
- * CameraDeviceSetup.getSessionCharacteristics} without having called {@link #addSurface}.</p>
+ * android.hardware.camera2.CameraDevice.CameraDeviceSetup#isSessionConfigurationSupported}
+ * and {@link
+ * android.hardware.camera2.CameraDevice.CameraDeviceSetup#getSessionCharacteristics} without
+ * having called {@link #addSurface}.</p>
*
* @param format The format of the ImageReader output. This must be one of the
* {@link android.graphics.ImageFormat} or {@link android.graphics.PixelFormat}
@@ -873,8 +879,10 @@
* before creating the capture session.</p>
*
* <p>An OutputConfiguration object created by this constructor can be used for {@link
- * CameraDeviceSetup.isSessionConfigurationSupported} and {@link
- * CameraDeviceSetup.getSessionCharacteristics} without having called {@link #addSurface}.</p>
+ * android.hardware.camera2.CameraDevice.CameraDeviceSetup#isSessionConfigurationSupported}
+ * and {@link
+ * android.hardware.camera2.CameraDevice.CameraDeviceSetup#getSessionCharacteristics} without
+ * having called {@link #addSurface}.</p>
*
* @param surfaceGroupId A group ID for this output, used for sharing memory between multiple
* outputs.
@@ -899,8 +907,10 @@
* before creating the capture session.</p>
*
* <p>An OutputConfiguration object created by this constructor can be used for {@link
- * CameraDeviceSetup.isSessionConfigurationSupported} and {@link
- * CameraDeviceSetup.getSessionCharacteristics} without having called {@link #addSurface}.</p>
+ * android.hardware.camera2.CameraDevice.CameraDeviceSetup#isSessionConfigurationSupported}
+ * and {@link
+ * android.hardware.camera2.CameraDevice.CameraDeviceSetup#getSessionCharacteristics} without
+ * having called {@link #addSurface}.</p>
*
* @param format The format of the ImageReader output. This must be one of the
* {@link android.graphics.ImageFormat} or {@link android.graphics.PixelFormat}
@@ -923,8 +933,10 @@
* before creating the capture session.</p>
*
* <p>An OutputConfiguration object created by this constructor can be used for {@link
- * CameraDeviceSetup.isSessionConfigurationSupported} and {@link
- * CameraDeviceSetup.getSessionCharacteristics} without having called {@link #addSurface}.</p>
+ * android.hardware.camera2.CameraDevice.CameraDeviceSetup#isSessionConfigurationSupported}
+ * and {@link
+ * android.hardware.camera2.CameraDevice.CameraDeviceSetup#getSessionCharacteristics} without
+ * having called {@link #addSurface}.</p>
*
* @param surfaceGroupId A group ID for this output, used for sharing memory between multiple
* outputs.
@@ -1171,9 +1183,9 @@
* <li>from {@link android.media.MediaRecorder} by calling
* {@link android.media.MediaRecorder#getSurface} or {@link
* android.media.MediaCodec#createPersistentInputSurface}</li>
- * <li>from {@link android.media.MediaCodce} by calling
- * {@link android.media.MediaCodec#createInputSurface} or {@link
- * android.media.MediaCodec#createPersistentInputSource}</li>
+ * <li>from {@link android.media.MediaCodec} by calling
+ * {@link android.media.MediaCodec#createInputSurface} or
+ * {@link android.media.MediaCodec#createPersistentInputSurface()}</li>
* </ul>
*
* <p> If the OutputConfiguration was constructed by {@link #OutputConfiguration(int, Size)}
diff --git a/core/java/android/hardware/location/ISignificantPlaceProvider.aidl b/core/java/android/hardware/location/ISignificantPlaceProvider.aidl
index e02169e..992dbff 100644
--- a/core/java/android/hardware/location/ISignificantPlaceProvider.aidl
+++ b/core/java/android/hardware/location/ISignificantPlaceProvider.aidl
@@ -7,4 +7,5 @@
*/
oneway interface ISignificantPlaceProvider {
void setSignificantPlaceProviderManager(in ISignificantPlaceProviderManager manager);
+ void onSignificantPlaceCheck();
}
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 278e863..943b04f 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -401,10 +401,7 @@
private long mStylusHwSessionsTimeout = STYLUS_HANDWRITING_IDLE_TIMEOUT_MS;
private Runnable mStylusWindowIdleTimeoutRunnable;
private long mStylusWindowIdleTimeoutForTest;
- /**
- * Tracks last {@link MotionEvent#getToolType(int)} used for {@link MotionEvent#ACTION_DOWN}.
- **/
- private int mLastUsedToolType;
+
/**
* Tracks the ctrl+shift shortcut
**/
@@ -720,6 +717,7 @@
final ViewTreeObserver.OnComputeInternalInsetsListener mInsetsComputer = info -> {
onComputeInsets(mTmpInsets);
+ mNavigationBarController.updateInsets(mTmpInsets);
if (!mViewsCreated) {
// The IME views are not ready, keep visible insets untouched.
mTmpInsets.visibleTopInsets = 0;
@@ -1367,7 +1365,6 @@
private void updateEditorToolTypeInternal(int toolType) {
if (Flags.useHandwritingListenerForTooltype()) {
- mLastUsedToolType = toolType;
if (mInputEditorInfo != null) {
mInputEditorInfo.setInitialToolType(toolType);
}
@@ -3384,9 +3381,6 @@
null /* icProto */);
mInputStarted = true;
mStartedInputConnection = ic;
- if (Flags.useHandwritingListenerForTooltype()) {
- editorInfo.setInitialToolType(mLastUsedToolType);
- }
mInputEditorInfo = editorInfo;
initialize();
mInlineSuggestionSessionController.notifyOnStartInput(
diff --git a/core/java/android/inputmethodservice/NavigationBarController.java b/core/java/android/inputmethodservice/NavigationBarController.java
index 9c55b0e..de67e06 100644
--- a/core/java/android/inputmethodservice/NavigationBarController.java
+++ b/core/java/android/inputmethodservice/NavigationBarController.java
@@ -58,6 +58,10 @@
final class NavigationBarController {
private interface Callback {
+
+ default void updateInsets(@NonNull InputMethodService.Insets originalInsets) {
+ }
+
default void updateTouchableInsets(@NonNull InputMethodService.Insets originalInsets,
@NonNull ViewTreeObserver.InternalInsetsInfo dest) {
}
@@ -96,6 +100,15 @@
? new Impl(inputMethodService) : Callback.NOOP;
}
+ /**
+ * Update the given insets to be at least as big as the IME navigation bar, when visible.
+ *
+ * @param originalInsets the insets to check and modify to include the IME navigation bar.
+ */
+ void updateInsets(@NonNull InputMethodService.Insets originalInsets) {
+ mImpl.updateInsets(originalInsets);
+ }
+
void updateTouchableInsets(@NonNull InputMethodService.Insets originalInsets,
@NonNull ViewTreeObserver.InternalInsetsInfo dest) {
mImpl.updateTouchableInsets(originalInsets, dest);
@@ -270,6 +283,24 @@
}
@Override
+ public void updateInsets(@NonNull InputMethodService.Insets originalInsets) {
+ if (!mImeDrawsImeNavBar || mNavigationBarFrame == null
+ || mNavigationBarFrame.getVisibility() != View.VISIBLE
+ || mService.isFullscreenMode()) {
+ return;
+ }
+
+ final int[] loc = new int[2];
+ mNavigationBarFrame.getLocationInWindow(loc);
+ if (originalInsets.contentTopInsets > loc[1]) {
+ originalInsets.contentTopInsets = loc[1];
+ }
+ if (originalInsets.visibleTopInsets > loc[1]) {
+ originalInsets.visibleTopInsets = loc[1];
+ }
+ }
+
+ @Override
public void updateTouchableInsets(@NonNull InputMethodService.Insets originalInsets,
@NonNull ViewTreeObserver.InternalInsetsInfo dest) {
if (!mImeDrawsImeNavBar || mNavigationBarFrame == null) {
diff --git a/core/java/android/os/BatteryConsumer.java b/core/java/android/os/BatteryConsumer.java
index 7bdd53d..02f3a25 100644
--- a/core/java/android/os/BatteryConsumer.java
+++ b/core/java/android/os/BatteryConsumer.java
@@ -200,6 +200,8 @@
POWER_COMPONENT_AUDIO,
POWER_COMPONENT_VIDEO,
POWER_COMPONENT_FLASHLIGHT,
+ POWER_COMPONENT_CAMERA,
+ POWER_COMPONENT_GNSS,
};
static final int COLUMN_INDEX_BATTERY_CONSUMER_TYPE = 0;
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 3e6223a..065b3d6 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -1994,7 +1994,8 @@
// STATES2 bits that are used for Power Stats tracking
public static final int IMPORTANT_FOR_POWER_STATS_STATES2 =
- STATE2_VIDEO_ON_FLAG | STATE2_FLASHLIGHT_FLAG | STATE2_CAMERA_FLAG;
+ STATE2_VIDEO_ON_FLAG | STATE2_FLASHLIGHT_FLAG | STATE2_CAMERA_FLAG
+ | STATE2_GPS_SIGNAL_QUALITY_MASK;
@UnsupportedAppUsage
public int states2;
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
old mode 100755
new mode 100644
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index fdce476..20522fa 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -1907,6 +1907,31 @@
"no_near_field_communication_radio";
/**
+ * This user restriction specifies if Near-field communication is disallowed to change
+ * on the device. If Near-field communication is disallowed it cannot be changed via Settings.
+ *
+ * <p>This restriction can only be set by a device owner or a profile owner of an
+ * organization-owned managed profile on the parent profile.
+ * In both cases, the restriction applies globally on the device and will not allow Near-field
+ * communication state being changed.
+ *
+ * <p>
+ * Near-field communication (NFC) is a radio technology that allows two devices (like your phone
+ * and a payments terminal) to communicate with each other when they're close together.
+ *
+ * <p>Default is <code>false</code>.
+ *
+ * <p>Key for user restrictions.
+ * <p>Type: Boolean
+ * @see DevicePolicyManager#addUserRestriction(ComponentName, String)
+ * @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
+ * @see #getUserRestrictions()
+ */
+ @FlaggedApi(Flags.FLAG_ENABLE_NFC_USER_RESTRICTION)
+ public static final String DISALLOW_CHANGE_NEAR_FIELD_COMMUNICATION_RADIO =
+ "no_change_near_field_communication_radio";
+
+ /**
* This user restriction specifies if Thread network is disallowed on the device. If Thread
* network is disallowed it cannot be turned on via Settings.
*
@@ -2007,6 +2032,7 @@
DISALLOW_CAMERA,
DISALLOW_CAMERA_TOGGLE,
DISALLOW_CELLULAR_2G,
+ DISALLOW_CHANGE_NEAR_FIELD_COMMUNICATION_RADIO,
DISALLOW_CHANGE_WIFI_STATE,
DISALLOW_CONFIG_BLUETOOTH,
DISALLOW_CONFIG_BRIGHTNESS,
diff --git a/core/java/android/service/wearable/WearableSensingService.java b/core/java/android/service/wearable/WearableSensingService.java
index ac22e70..3735c43 100644
--- a/core/java/android/service/wearable/WearableSensingService.java
+++ b/core/java/android/service/wearable/WearableSensingService.java
@@ -398,8 +398,8 @@
/**
* Called when a data request observer is registered. Each request must not be larger than
* {@link WearableSensingDataRequest#getMaxRequestSize()}. In addition, at most {@link
- * WearableSensingDataRequester#getRateLimit()} requests can be sent every rolling {@link
- * WearableSensingDataRequester#getRateLimitWindowSize()}. Requests that are too large or too
+ * WearableSensingDataRequest#getRateLimit()} requests can be sent every rolling {@link
+ * WearableSensingDataRequest#getRateLimitWindowSize()}. Requests that are too large or too
* frequent will be dropped by the system. See {@link
* WearableSensingDataRequester#requestData(WearableSensingDataRequest, Consumer)} for details
* about the status code returned for each request.
@@ -442,7 +442,7 @@
* @param packageName The package name of the app that will receive the requests sent to the
* dataRequester.
* @param dataRequester A handle to the observer to be unregistered. It is the exact same
- * instance provided in a previous {@link #onDataRequestConsumerRegistered(int, String,
+ * instance provided in a previous {@link #onDataRequestObserverRegistered(int, String,
* WearableSensingDataRequester, Consumer)} invocation.
* @param statusConsumer the consumer for the status of the data request observer
* unregistration. This is different from the status for each data request.
@@ -469,7 +469,7 @@
* in which case it should return the corresponding status code.
*
* <p>The implementation should also store the {@code statusConsumer}. If the wearable stops
- * listening for hotword for any reason other than {@link #onStopListeningForHotword(Consumer)}
+ * listening for hotword for any reason other than {@link #onStopHotwordRecognition(Consumer)}
* being invoked, it should send an appropriate status code listed in {@link
* WearableSensingManager} to {@code statusConsumer}. If the error condition cannot be described
* by any of those status codes, it should send a {@link WearableSensingManager#STATUS_UNKNOWN}.
@@ -514,11 +514,11 @@
/**
* Called when hotword audio data sent to the {@code hotwordAudioConsumer} in {@link
- * #onStartListeningForHotword(Consumer, Consumer)} is accepted by the
+ * #onStartHotwordRecognition(Consumer, Consumer)} is accepted by the
* {@link android.service.voice.HotwordDetectionService} as valid hotword.
*
* <p>After the implementation of this class sends the hotword audio data to the {@code
- * hotwordAudioConsumer} in {@link #onStartListeningForHotword(Consumer,
+ * hotwordAudioConsumer} in {@link #onStartHotwordRecognition(Consumer,
* Consumer)}, the system will forward the data into {@link
* android.service.voice.HotwordDetectionService} (which runs in an isolated process) for
* second-stage hotword detection. If accepted as valid hotword there, this method will be
@@ -545,7 +545,7 @@
*
* <p>This method is expected to be overridden by a derived class. The implementation should
* stop sending hotword audio data to the {@code hotwordAudioConsumer} in {@link
- * #onStartListeningForHotword(Consumer, Consumer)}
+ * #onStartHotwordRecognition(Consumer, Consumer)}
*/
@FlaggedApi(Flags.FLAG_ENABLE_HOTWORD_WEARABLE_SENSING_API)
@BinderThread
diff --git a/core/java/android/telephony/SubscriptionPlan.aidl b/core/java/android/telephony/SubscriptionPlan.aidl
old mode 100755
new mode 100644
diff --git a/core/java/android/text/format/DateFormat.java b/core/java/android/text/format/DateFormat.java
old mode 100755
new mode 100644
diff --git a/core/java/android/util/DisplayMetrics.java b/core/java/android/util/DisplayMetrics.java
old mode 100755
new mode 100644
diff --git a/core/java/android/view/HdrRenderState.java b/core/java/android/view/HdrRenderState.java
index eadc507..c6b3937 100644
--- a/core/java/android/view/HdrRenderState.java
+++ b/core/java/android/view/HdrRenderState.java
@@ -65,6 +65,7 @@
void startListening() {
if (isHdrEnabled() && !mIsListenerRegistered && mViewRoot.mDisplay != null) {
mViewRoot.mDisplay.registerHdrSdrRatioChangedListener(mViewRoot.mExecutor, this);
+ mIsListenerRegistered = true;
}
}
diff --git a/core/java/android/view/SurfaceControlRegistry.java b/core/java/android/view/SurfaceControlRegistry.java
index 127d4a7..aa3654d 100644
--- a/core/java/android/view/SurfaceControlRegistry.java
+++ b/core/java/android/view/SurfaceControlRegistry.java
@@ -342,12 +342,14 @@
return false;
}
final boolean matchName = !sCallStackDebuggingMatchName.isEmpty();
- if (matchName && (name == null
- || !sCallStackDebuggingMatchName.contains(name.toLowerCase()))) {
- // Skip if target surface doesn't match requested surface
+ if (!matchName) {
+ return true;
+ }
+ if (name == null) {
return false;
}
- return true;
+ return sCallStackDebuggingMatchName.contains(name.toLowerCase()) ||
+ name.toLowerCase().contains(sCallStackDebuggingMatchName);
}
/**
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 14bb681..9bc1511 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -7152,7 +7152,7 @@
public void setPendingCredentialRequest(@NonNull GetCredentialRequest request,
@NonNull OutcomeReceiver<GetCredentialResponse, GetCredentialException> callback) {
Preconditions.checkNotNull(request, "request must not be null");
- Preconditions.checkNotNull(callback, "request must not be null");
+ Preconditions.checkNotNull(callback, "callback must not be null");
for (CredentialOption option : request.getCredentialOptions()) {
ArrayList<AutofillId> ids = option.getCandidateQueryData()
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index cb82278..a26150c 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -177,7 +177,6 @@
import android.graphics.RenderNode;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
-import android.hardware.SyncFence;
import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManager.DisplayListener;
import android.hardware.display.DisplayManagerGlobal;
@@ -203,6 +202,7 @@
import android.os.UserHandle;
import android.provider.Settings;
import android.sysprop.DisplayProperties;
+import android.sysprop.ViewProperties;
import android.text.TextUtils;
import android.util.AndroidRuntimeException;
import android.util.DisplayMetrics;
@@ -219,7 +219,6 @@
import android.view.InputDevice.InputSourceClass;
import android.view.Surface.OutOfResourcesException;
import android.view.SurfaceControl.Transaction;
-import android.view.SurfaceControl.TransactionStats;
import android.view.View.AttachInfo;
import android.view.View.FocusDirection;
import android.view.View.MeasureSpec;
@@ -294,7 +293,6 @@
import java.util.Queue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
-import java.util.function.Consumer;
import java.util.function.Predicate;
/**
* The top of a view hierarchy, implementing the needed protocol between View
@@ -1191,13 +1189,6 @@
private String mFpsTraceName;
private String mLargestViewTraceName;
- private final boolean mAppStartInfoTimestampsFlagValue;
- @GuardedBy("this")
- private boolean mAppStartTimestampsSent = false;
- private boolean mAppStartTrackingStarted = false;
- private long mRenderThreadDrawStartTimeNs = -1;
- private long mFirstFramePresentedTimeNs = -1;
-
private static boolean sToolkitSetFrameRateReadOnlyFlagValue;
private static boolean sToolkitFrameRateFunctionEnablingReadOnlyFlagValue;
private static boolean sToolkitMetricsForFrameRateDecisionFlagValue;
@@ -1209,6 +1200,7 @@
Flags.enableInvalidateCheckThread();
private static boolean sSurfaceFlingerBugfixFlagValue =
com.android.graphics.surfaceflinger.flags.Flags.vrrBugfix24q4();
+ private static final boolean sEnableVrr = ViewProperties.vrr_enabled().orElse(true);
static {
sToolkitSetFrameRateReadOnlyFlagValue = toolkitSetFrameRateReadOnly();
@@ -1314,8 +1306,6 @@
} else {
mSensitiveContentProtectionService = null;
}
-
- mAppStartInfoTimestampsFlagValue = android.app.Flags.appStartInfoTimestamps();
}
public static void addFirstDrawHandler(Runnable callback) {
@@ -2588,12 +2578,6 @@
notifySurfaceDestroyed();
}
destroySurface();
-
- // Reset so they can be sent again for warm starts.
- mAppStartTimestampsSent = false;
- mAppStartTrackingStarted = false;
- mRenderThreadDrawStartTimeNs = -1;
- mFirstFramePresentedTimeNs = -1;
}
}
}
@@ -4392,30 +4376,6 @@
reportDrawFinished(t, seqId);
}
});
-
- // Only trigger once per {@link ViewRootImpl} instance, so don't add listener if
- // {link mTransactionCompletedTimeNs} has already been set.
- if (mAppStartInfoTimestampsFlagValue && !mAppStartTrackingStarted) {
- mAppStartTrackingStarted = true;
- Transaction transaction = new Transaction();
- transaction.addTransactionCompletedListener(mExecutor,
- new Consumer<TransactionStats>() {
- @Override
- public void accept(TransactionStats transactionStats) {
- SyncFence presentFence = transactionStats.getPresentFence();
- if (presentFence.awaitForever()) {
- if (mFirstFramePresentedTimeNs == -1) {
- // Only trigger once per {@link ViewRootImpl} instance.
- mFirstFramePresentedTimeNs = presentFence.getSignalTime();
- maybeSendAppStartTimes();
- }
- }
- presentFence.close();
- }
- });
- applyTransactionOnDraw(transaction);
- }
-
if (DEBUG_BLAST) {
Log.d(mTag, "Setup new sync=" + mWmsRequestSyncGroup.getName());
}
@@ -4423,45 +4383,6 @@
mWmsRequestSyncGroup.add(this, null /* runnable */);
}
- private void maybeSendAppStartTimes() {
- synchronized (this) {
- if (mAppStartTimestampsSent) {
- // Don't send timestamps more than once.
- return;
- }
-
- // If we already have {@link mRenderThreadDrawStartTimeNs} then pass it through, if not
- // post to main thread and check if we have it there.
- if (mRenderThreadDrawStartTimeNs != -1) {
- sendAppStartTimesLocked();
- } else {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- synchronized (ViewRootImpl.this) {
- if (mRenderThreadDrawStartTimeNs == -1) {
- return;
- }
- sendAppStartTimesLocked();
- }
- }
- });
- }
- }
- }
-
- @GuardedBy("this")
- private void sendAppStartTimesLocked() {
- try {
- ActivityManager.getService().reportStartInfoViewTimestamps(
- mRenderThreadDrawStartTimeNs, mFirstFramePresentedTimeNs);
- mAppStartTimestampsSent = true;
- } catch (RemoteException e) {
- // Ignore, timestamps may be lost.
- if (DBG) Log.d(TAG, "Exception attempting to report start timestamps.", e);
- }
- }
-
/**
* Helper used to notify the service to block projection when a sensitive
* view (the view displays sensitive content) is attached to the window.
@@ -5648,13 +5569,7 @@
registerCallbackForPendingTransactions();
}
- long timeNs = SystemClock.uptimeNanos();
mAttachInfo.mThreadedRenderer.draw(mView, mAttachInfo, this);
-
- // Only trigger once per {@link ViewRootImpl} instance.
- if (mAppStartInfoTimestampsFlagValue && mRenderThreadDrawStartTimeNs == -1) {
- mRenderThreadDrawStartTimeNs = timeNs;
- }
} else {
// If we get here with a disabled & requested hardware renderer, something went
// wrong (an invalidate posted right before we destroyed the hardware surface
@@ -7504,8 +7419,6 @@
final KeyEvent event = (KeyEvent)q.mEvent;
if (mView.dispatchKeyEventPreIme(event)) {
return FINISH_HANDLED;
- } else if (q.forPreImeOnly()) {
- return FINISH_NOT_HANDLED;
}
return FORWARD;
}
@@ -10002,7 +9915,6 @@
public static final int FLAG_RESYNTHESIZED = 1 << 4;
public static final int FLAG_UNHANDLED = 1 << 5;
public static final int FLAG_MODIFIED_FOR_COMPATIBILITY = 1 << 6;
- public static final int FLAG_PRE_IME_ONLY = 1 << 7;
public QueuedInputEvent mNext;
@@ -10010,13 +9922,6 @@
public InputEventReceiver mReceiver;
public int mFlags;
- public boolean forPreImeOnly() {
- if ((mFlags & FLAG_PRE_IME_ONLY) != 0) {
- return true;
- }
- return false;
- }
-
public boolean shouldSkipIme() {
if ((mFlags & FLAG_DELIVER_POST_IME) != 0) {
return true;
@@ -10043,7 +9948,6 @@
hasPrevious = flagToString("FINISHED_HANDLED", FLAG_FINISHED_HANDLED, hasPrevious, sb);
hasPrevious = flagToString("RESYNTHESIZED", FLAG_RESYNTHESIZED, hasPrevious, sb);
hasPrevious = flagToString("UNHANDLED", FLAG_UNHANDLED, hasPrevious, sb);
- hasPrevious = flagToString("FLAG_PRE_IME_ONLY", FLAG_PRE_IME_ONLY, hasPrevious, sb);
if (!hasPrevious) {
sb.append("0");
}
@@ -10100,7 +10004,7 @@
}
@UnsupportedAppUsage
- QueuedInputEvent enqueueInputEvent(InputEvent event,
+ void enqueueInputEvent(InputEvent event,
InputEventReceiver receiver, int flags, boolean processImmediately) {
QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags);
@@ -10139,7 +10043,6 @@
} else {
scheduleProcessInputEvents();
}
- return q;
}
private void scheduleProcessInputEvents() {
@@ -12461,45 +12364,29 @@
+ "IWindow:%s Session:%s",
mOnBackInvokedDispatcher, mBasePackageName, mWindow, mWindowSession));
}
- mOnBackInvokedDispatcher.attachToWindow(mWindowSession, mWindow, this,
+ mOnBackInvokedDispatcher.attachToWindow(mWindowSession, mWindow,
mImeBackAnimationController);
}
- /**
- * Sends {@link KeyEvent#ACTION_DOWN ACTION_DOWN} and {@link KeyEvent#ACTION_UP ACTION_UP}
- * back key events
- *
- * @param preImeOnly whether the back events should be sent to the pre-ime stage only
- * @return whether the event was handled (i.e. onKeyPreIme consumed it if preImeOnly=true)
- */
- public boolean injectBackKeyEvents(boolean preImeOnly) {
- boolean consumed;
- try {
- processingBackKey(true);
- sendBackKeyEvent(KeyEvent.ACTION_DOWN, preImeOnly);
- consumed = sendBackKeyEvent(KeyEvent.ACTION_UP, preImeOnly);
- } finally {
- processingBackKey(false);
- }
- return consumed;
- }
-
- private boolean sendBackKeyEvent(int action, boolean preImeOnly) {
+ private void sendBackKeyEvent(int action) {
long when = SystemClock.uptimeMillis();
final KeyEvent ev = new KeyEvent(when, when, action,
KeyEvent.KEYCODE_BACK, 0 /* repeat */, 0 /* metaState */,
KeyCharacterMap.VIRTUAL_KEYBOARD, 0 /* scancode */,
KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY,
InputDevice.SOURCE_KEYBOARD);
- int flags = preImeOnly ? QueuedInputEvent.FLAG_PRE_IME_ONLY : 0;
- QueuedInputEvent q = enqueueInputEvent(ev, null /* receiver */, flags,
- true /* processImmediately */);
- return (q.mFlags & QueuedInputEvent.FLAG_FINISHED_HANDLED) != 0;
+ enqueueInputEvent(ev, null /* receiver */, 0 /* flags */, true /* processImmediately */);
}
private void registerCompatOnBackInvokedCallback() {
mCompatOnBackInvokedCallback = () -> {
- injectBackKeyEvents(/* preImeOnly */ false);
+ try {
+ processingBackKey(true);
+ sendBackKeyEvent(KeyEvent.ACTION_DOWN);
+ sendBackKeyEvent(KeyEvent.ACTION_UP);
+ } finally {
+ processingBackKey(false);
+ }
};
if (mOnBackInvokedDispatcher.hasImeOnBackInvokedDispatcher()) {
Log.d(TAG, "Skip registering CompatOnBackInvokedCallback on IME dispatcher");
@@ -12952,13 +12839,13 @@
private boolean shouldSetFrameRateCategory() {
// use toolkitSetFrameRate flag to gate the change
- return mSurface.isValid() && shouldEnableDvrr();
+ return shouldEnableDvrr() && mSurface.isValid() && shouldEnableDvrr();
}
private boolean shouldSetFrameRate() {
// use toolkitSetFrameRate flag to gate the change
- return mSurface.isValid() && mPreferredFrameRate >= 0
- && shouldEnableDvrr() && !mIsFrameRateConflicted;
+ return shouldEnableDvrr() && mSurface.isValid() && mPreferredFrameRate >= 0
+ && !mIsFrameRateConflicted;
}
private boolean shouldTouchBoost(int motionEventAction, int windowType) {
@@ -12993,7 +12880,7 @@
* @param view The View with the ThreadedRenderer animation that started.
*/
public void addThreadedRendererView(View view) {
- if (!mThreadedRendererViews.contains(view)) {
+ if (shouldEnableDvrr() && !mThreadedRendererViews.contains(view)) {
mThreadedRendererViews.add(view);
}
}
@@ -13005,7 +12892,8 @@
*/
public void removeThreadedRendererView(View view) {
mThreadedRendererViews.remove(view);
- if (!mInvalidationIdleMessagePosted && sSurfaceFlingerBugfixFlagValue) {
+ if (shouldEnableDvrr()
+ && !mInvalidationIdleMessagePosted && sSurfaceFlingerBugfixFlagValue) {
mInvalidationIdleMessagePosted = true;
mHandler.sendEmptyMessageDelayed(MSG_CHECK_INVALIDATION_IDLE, IDLE_TIME_MILLIS);
}
@@ -13226,7 +13114,7 @@
private boolean shouldEnableDvrr() {
// uncomment this when we are ready for enabling dVRR
- if (sToolkitFrameRateViewEnablingReadOnlyFlagValue) {
+ if (sEnableVrr && sToolkitFrameRateViewEnablingReadOnlyFlagValue) {
return sToolkitSetFrameRateReadOnlyFlagValue && isFrameRatePowerSavingsBalanced();
}
return false;
diff --git a/core/java/android/view/autofill/AutofillFeatureFlags.java b/core/java/android/view/autofill/AutofillFeatureFlags.java
index 46b41ae..950dfee 100644
--- a/core/java/android/view/autofill/AutofillFeatureFlags.java
+++ b/core/java/android/view/autofill/AutofillFeatureFlags.java
@@ -548,7 +548,7 @@
return DeviceConfig.getBoolean(
DeviceConfig.NAMESPACE_AUTOFILL,
DEVICE_CONFIG_FILL_FIELDS_FROM_CURRENT_SESSION_ONLY,
- false);
+ true);
}
/**
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 9cc4191..ad513f1 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -3575,40 +3575,14 @@
// isCredential field indicates that the developer might be calling Credman, and we should
// suppress autofill dialogs. But it is not a good enough indicator that there is a valid
// credman option.
- if (view.isCredential()) {
- return true;
- }
- return containsAutofillHintPrefix(view, View.AUTOFILL_HINT_CREDENTIAL_MANAGER);
+ return view.isCredential() || isCredmanRequested(view);
}
private boolean isCredmanRequested(View view) {
if (view == null) {
return false;
}
- if (view.getViewCredentialHandler() != null) {
- return true;
- }
-
- String[] hints = view.getAutofillHints();
- if (hints == null) {
- return false;
- }
- // if hint starts with 'credential=', then we assume that there is a valid
- // credential option set by the client.
- return containsAutofillHintPrefix(view, View.AUTOFILL_HINT_CREDENTIAL_MANAGER + "=");
- }
-
- private boolean containsAutofillHintPrefix(View view, String prefix) {
- String[] hints = view.getAutofillHints();
- if (hints == null) {
- return false;
- }
- for (String hint : hints) {
- if (hint != null && hint.startsWith(prefix)) {
- return true;
- }
- }
- return false;
+ return view.getViewCredentialHandler() != null;
}
/**
diff --git a/core/java/android/widget/CursorTreeAdapter.java b/core/java/android/widget/CursorTreeAdapter.java
old mode 100755
new mode 100644
diff --git a/core/java/android/widget/DatePickerCalendarDelegate.java b/core/java/android/widget/DatePickerCalendarDelegate.java
old mode 100755
new mode 100644
diff --git a/core/java/android/widget/ListPopupWindow.java b/core/java/android/widget/ListPopupWindow.java
old mode 100755
new mode 100644
diff --git a/core/java/android/widget/SearchView.java b/core/java/android/widget/SearchView.java
old mode 100755
new mode 100644
diff --git a/core/java/android/window/BackNavigationInfo.java b/core/java/android/window/BackNavigationInfo.java
index f24bc74..57bded7 100644
--- a/core/java/android/window/BackNavigationInfo.java
+++ b/core/java/android/window/BackNavigationInfo.java
@@ -23,6 +23,7 @@
import android.annotation.Nullable;
import android.annotation.TestApi;
import android.graphics.Color;
+import android.graphics.Rect;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
@@ -113,6 +114,8 @@
private final CustomAnimationInfo mCustomAnimationInfo;
private final int mLetterboxColor;
+ @NonNull
+ private final Rect mTouchableRegion;
/**
* Create a new {@link BackNavigationInfo} instance.
@@ -128,7 +131,8 @@
boolean isPrepareRemoteAnimation,
boolean isAnimationCallback,
@Nullable CustomAnimationInfo customAnimationInfo,
- int letterboxColor) {
+ int letterboxColor,
+ @Nullable Rect touchableRegion) {
mType = type;
mOnBackNavigationDone = onBackNavigationDone;
mOnBackInvokedCallback = onBackInvokedCallback;
@@ -136,6 +140,7 @@
mAnimationCallback = isAnimationCallback;
mCustomAnimationInfo = customAnimationInfo;
mLetterboxColor = letterboxColor;
+ mTouchableRegion = new Rect(touchableRegion);
}
private BackNavigationInfo(@NonNull Parcel in) {
@@ -146,6 +151,7 @@
mAnimationCallback = in.readBoolean();
mCustomAnimationInfo = in.readTypedObject(CustomAnimationInfo.CREATOR);
mLetterboxColor = in.readInt();
+ mTouchableRegion = in.readTypedObject(Rect.CREATOR);
}
/** @hide */
@@ -158,6 +164,7 @@
dest.writeBoolean(mAnimationCallback);
dest.writeTypedObject(mCustomAnimationInfo, flags);
dest.writeInt(mLetterboxColor);
+ dest.writeTypedObject(mTouchableRegion, flags);
}
/**
@@ -206,6 +213,16 @@
public int getLetterboxColor() {
return mLetterboxColor;
}
+
+ /**
+ * @return The app window region where the client can handle touch event.
+ * @hide
+ */
+ @NonNull
+ public Rect getTouchableRegion() {
+ return mTouchableRegion;
+ }
+
/**
* Callback to be called when the back preview is finished in order to notify the server that
* it can clean up the resources created for the animation.
@@ -402,6 +419,7 @@
private boolean mAnimationCallback = false;
private int mLetterboxColor = Color.TRANSPARENT;
+ private Rect mTouchableRegion;
/**
* @see BackNavigationInfo#getType()
@@ -478,6 +496,13 @@
}
/**
+ * @param rect Non-empty for frame of current focus window.
+ */
+ public Builder setTouchableRegion(Rect rect) {
+ mTouchableRegion = new Rect(rect);
+ return this;
+ }
+ /**
* Builds and returns an instance of {@link BackNavigationInfo}
*/
public BackNavigationInfo build() {
@@ -486,7 +511,8 @@
mPrepareRemoteAnimation,
mAnimationCallback,
mCustomAnimationInfo,
- mLetterboxColor);
+ mLetterboxColor,
+ mTouchableRegion);
}
}
}
diff --git a/core/java/android/window/WindowOnBackInvokedDispatcher.java b/core/java/android/window/WindowOnBackInvokedDispatcher.java
index 4c993c2..4ca64e7 100644
--- a/core/java/android/window/WindowOnBackInvokedDispatcher.java
+++ b/core/java/android/window/WindowOnBackInvokedDispatcher.java
@@ -37,7 +37,6 @@
import android.view.IWindowSession;
import android.view.ImeBackAnimationController;
import android.view.MotionEvent;
-import android.view.ViewRootImpl;
import androidx.annotation.VisibleForTesting;
@@ -50,7 +49,6 @@
import java.util.HashMap;
import java.util.Objects;
import java.util.TreeMap;
-import java.util.function.BooleanSupplier;
import java.util.function.Supplier;
/**
@@ -70,7 +68,6 @@
public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
private IWindowSession mWindowSession;
private IWindow mWindow;
- private ViewRootImpl mViewRoot;
@VisibleForTesting
public final BackTouchTracker mTouchTracker = new BackTouchTracker();
@VisibleForTesting
@@ -137,12 +134,10 @@
* is attached a window.
*/
public void attachToWindow(@NonNull IWindowSession windowSession, @NonNull IWindow window,
- @Nullable ViewRootImpl viewRoot,
@Nullable ImeBackAnimationController imeBackAnimationController) {
synchronized (mLock) {
mWindowSession = windowSession;
mWindow = window;
- mViewRoot = viewRoot;
mImeBackAnimationController = imeBackAnimationController;
if (!mAllCallbacks.isEmpty()) {
setTopOnBackInvokedCallback(getTopCallback());
@@ -156,7 +151,6 @@
clear();
mWindow = null;
mWindowSession = null;
- mViewRoot = null;
mImeBackAnimationController = null;
}
}
@@ -182,6 +176,8 @@
return;
}
if (callback instanceof ImeOnBackInvokedDispatcher.ImeOnBackInvokedCallback) {
+ // Fall back to compat back key injection if legacy back behaviour should be used.
+ if (!isOnBackInvokedCallbackEnabled()) return;
if (callback instanceof ImeOnBackInvokedDispatcher.DefaultImeOnBackAnimationCallback
&& mImeBackAnimationController != null) {
// register ImeBackAnimationController instead to play predictive back animation
@@ -304,14 +300,6 @@
}
}
- private boolean callOnKeyPreIme() {
- if (mViewRoot != null && !isOnBackInvokedCallbackEnabled(mViewRoot.mContext)) {
- return mViewRoot.injectBackKeyEvents(/*preImeOnly*/ true);
- } else {
- return false;
- }
- }
-
private void setTopOnBackInvokedCallback(@Nullable OnBackInvokedCallback callback) {
if (mWindowSession == null || mWindow == null) {
return;
@@ -320,8 +308,8 @@
OnBackInvokedCallbackInfo callbackInfo = null;
if (callback != null) {
int priority = mAllCallbacks.get(callback);
- final IOnBackInvokedCallback iCallback = new OnBackInvokedCallbackWrapper(callback,
- mTouchTracker, mProgressAnimator, mHandler, this::callOnKeyPreIme);
+ final IOnBackInvokedCallback iCallback = new OnBackInvokedCallbackWrapper(
+ callback, mTouchTracker, mProgressAnimator, mHandler);
callbackInfo = new OnBackInvokedCallbackInfo(
iCallback,
priority,
@@ -411,20 +399,16 @@
private final BackTouchTracker mTouchTracker;
@NonNull
private final Handler mHandler;
- @NonNull
- private final BooleanSupplier mOnKeyPreIme;
OnBackInvokedCallbackWrapper(
@NonNull OnBackInvokedCallback callback,
@NonNull BackTouchTracker touchTracker,
@NonNull BackProgressAnimator progressAnimator,
- @NonNull Handler handler,
- @NonNull BooleanSupplier onKeyPreIme) {
+ @NonNull Handler handler) {
mCallback = new WeakReference<>(callback);
mTouchTracker = touchTracker;
mProgressAnimator = progressAnimator;
mHandler = handler;
- mOnKeyPreIme = onKeyPreIme;
}
@Override
@@ -451,7 +435,16 @@
}
@Override
- public void onBackProgressed(BackMotionEvent backEvent) { }
+ public void onBackProgressed(BackMotionEvent backEvent) {
+ // This is only called in some special cases such as when activity embedding is active
+ // or when the activity is letterboxed. Otherwise mProgressAnimator#onBackProgressed is
+ // called from WindowOnBackInvokedDispatcher#onMotionEvent
+ mHandler.post(() -> {
+ if (getBackAnimationCallback() != null) {
+ mProgressAnimator.onBackProgressed(backEvent);
+ }
+ });
+ }
@Override
public void onBackCancelled() {
@@ -467,7 +460,6 @@
public void onBackInvoked() throws RemoteException {
mHandler.post(() -> {
mTouchTracker.reset();
- if (consumedByOnKeyPreIme()) return;
boolean isInProgress = mProgressAnimator.isBackAnimationInProgress();
final OnBackInvokedCallback callback = mCallback.get();
if (callback == null) {
@@ -489,30 +481,6 @@
});
}
- private boolean consumedByOnKeyPreIme() {
- final OnBackInvokedCallback callback = mCallback.get();
- if (callback instanceof ImeBackAnimationController
- || callback instanceof ImeOnBackInvokedDispatcher.ImeOnBackInvokedCallback) {
- // call onKeyPreIme API if the current callback is an IME callback and the app has
- // not set enableOnBackInvokedCallback="false"
- try {
- boolean consumed = mOnKeyPreIme.getAsBoolean();
- if (consumed) {
- // back event intercepted by app in onKeyPreIme -> cancel the IME animation.
- final OnBackAnimationCallback animationCallback =
- getBackAnimationCallback();
- if (animationCallback != null) {
- mProgressAnimator.onBackCancelled(animationCallback::onBackCancelled);
- }
- return true;
- }
- } catch (Exception e) {
- Log.d(TAG, "Failed to call onKeyPreIme", e);
- }
- }
- return false;
- }
-
@Override
public void setTriggerBack(boolean triggerBack) throws RemoteException {
mTouchTracker.setTriggerBack(triggerBack);
diff --git a/core/java/android/window/flags/lse_desktop_experience.aconfig b/core/java/android/window/flags/lse_desktop_experience.aconfig
index daf2fe3..ca125da 100644
--- a/core/java/android/window/flags/lse_desktop_experience.aconfig
+++ b/core/java/android/window/flags/lse_desktop_experience.aconfig
@@ -106,3 +106,17 @@
description: "Whether to apply Camera Compat treatment to fixed-orientation apps in desktop windowing mode"
bug: "314952133"
}
+
+flag {
+ name: "enable_task_stack_observer_in_shell"
+ namespace: "lse_desktop_experience"
+ description: "Introduces a new observer in shell to track the task stack."
+ bug: "341932484"
+}
+
+flag {
+ name: "enable_desktop_windowing_size_constraints"
+ namespace: "lse_desktop_experience"
+ description: "Whether to enable min/max window size constraints when resizing a window in desktop windowing mode"
+ bug: "327589741"
+}
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 98d6ec6..920981e 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -923,7 +923,7 @@
mSystemWindowInsets = insets.getSystemWindowInsets();
mResolverDrawerLayout.setPadding(mSystemWindowInsets.left, mSystemWindowInsets.top,
- mSystemWindowInsets.right, mSystemWindowInsets.bottom);
+ mSystemWindowInsets.right, 0);
resetButtonBar();
@@ -952,7 +952,7 @@
if (mSystemWindowInsets != null) {
mResolverDrawerLayout.setPadding(mSystemWindowInsets.left, mSystemWindowInsets.top,
- mSystemWindowInsets.right, mSystemWindowInsets.bottom);
+ mSystemWindowInsets.right, 0);
}
}
diff --git a/core/java/com/android/internal/util/function/pooled/OmniFunction.java b/core/java/com/android/internal/util/function/pooled/OmniFunction.java
old mode 100755
new mode 100644
diff --git a/core/java/com/android/internal/util/function/pooled/PooledLambda.java b/core/java/com/android/internal/util/function/pooled/PooledLambda.java
old mode 100755
new mode 100644
diff --git a/core/java/com/android/internal/util/function/pooled/PooledLambdaImpl.java b/core/java/com/android/internal/util/function/pooled/PooledLambdaImpl.java
old mode 100755
new mode 100644
diff --git a/core/jni/android_view_MotionEvent.cpp b/core/jni/android_view_MotionEvent.cpp
index f914bee..d32486c 100644
--- a/core/jni/android_view_MotionEvent.cpp
+++ b/core/jni/android_view_MotionEvent.cpp
@@ -203,55 +203,52 @@
return true;
}
-static void pointerCoordsToNative(JNIEnv* env, jobject pointerCoordsObj,
- float xOffset, float yOffset, PointerCoords* outRawPointerCoords) {
- outRawPointerCoords->clear();
- outRawPointerCoords->setAxisValue(AMOTION_EVENT_AXIS_X,
- env->GetFloatField(pointerCoordsObj, gPointerCoordsClassInfo.x) - xOffset);
- outRawPointerCoords->setAxisValue(AMOTION_EVENT_AXIS_Y,
- env->GetFloatField(pointerCoordsObj, gPointerCoordsClassInfo.y) - yOffset);
- outRawPointerCoords->setAxisValue(AMOTION_EVENT_AXIS_PRESSURE,
- env->GetFloatField(pointerCoordsObj, gPointerCoordsClassInfo.pressure));
- outRawPointerCoords->setAxisValue(AMOTION_EVENT_AXIS_SIZE,
- env->GetFloatField(pointerCoordsObj, gPointerCoordsClassInfo.size));
- outRawPointerCoords->setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR,
- env->GetFloatField(pointerCoordsObj, gPointerCoordsClassInfo.touchMajor));
- outRawPointerCoords->setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR,
- env->GetFloatField(pointerCoordsObj, gPointerCoordsClassInfo.touchMinor));
- outRawPointerCoords->setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR,
- env->GetFloatField(pointerCoordsObj, gPointerCoordsClassInfo.toolMajor));
- outRawPointerCoords->setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR,
- env->GetFloatField(pointerCoordsObj, gPointerCoordsClassInfo.toolMinor));
- outRawPointerCoords->setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION,
- env->GetFloatField(pointerCoordsObj, gPointerCoordsClassInfo.orientation));
- outRawPointerCoords->setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X,
- env->GetFloatField(pointerCoordsObj,
- gPointerCoordsClassInfo.relativeX));
- outRawPointerCoords->setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y,
- env->GetFloatField(pointerCoordsObj,
- gPointerCoordsClassInfo.relativeY));
- outRawPointerCoords->isResampled =
- env->GetBooleanField(pointerCoordsObj, gPointerCoordsClassInfo.isResampled);
+static PointerCoords pointerCoordsToNative(JNIEnv* env, jobject pointerCoordsObj) {
+ PointerCoords out{};
+ out.setAxisValue(AMOTION_EVENT_AXIS_X,
+ env->GetFloatField(pointerCoordsObj, gPointerCoordsClassInfo.x));
+ out.setAxisValue(AMOTION_EVENT_AXIS_Y,
+ env->GetFloatField(pointerCoordsObj, gPointerCoordsClassInfo.y));
+ out.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE,
+ env->GetFloatField(pointerCoordsObj, gPointerCoordsClassInfo.pressure));
+ out.setAxisValue(AMOTION_EVENT_AXIS_SIZE,
+ env->GetFloatField(pointerCoordsObj, gPointerCoordsClassInfo.size));
+ out.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR,
+ env->GetFloatField(pointerCoordsObj, gPointerCoordsClassInfo.touchMajor));
+ out.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR,
+ env->GetFloatField(pointerCoordsObj, gPointerCoordsClassInfo.touchMinor));
+ out.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR,
+ env->GetFloatField(pointerCoordsObj, gPointerCoordsClassInfo.toolMajor));
+ out.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR,
+ env->GetFloatField(pointerCoordsObj, gPointerCoordsClassInfo.toolMinor));
+ out.setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION,
+ env->GetFloatField(pointerCoordsObj, gPointerCoordsClassInfo.orientation));
+ out.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X,
+ env->GetFloatField(pointerCoordsObj, gPointerCoordsClassInfo.relativeX));
+ out.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y,
+ env->GetFloatField(pointerCoordsObj, gPointerCoordsClassInfo.relativeY));
+ out.isResampled = env->GetBooleanField(pointerCoordsObj, gPointerCoordsClassInfo.isResampled);
BitSet64 bits =
BitSet64(env->GetLongField(pointerCoordsObj, gPointerCoordsClassInfo.mPackedAxisBits));
if (!bits.isEmpty()) {
- jfloatArray valuesArray = jfloatArray(env->GetObjectField(pointerCoordsObj,
- gPointerCoordsClassInfo.mPackedAxisValues));
+ jfloatArray valuesArray = jfloatArray(
+ env->GetObjectField(pointerCoordsObj, gPointerCoordsClassInfo.mPackedAxisValues));
if (valuesArray) {
- jfloat* values = static_cast<jfloat*>(
- env->GetPrimitiveArrayCritical(valuesArray, NULL));
+ jfloat* values =
+ static_cast<jfloat*>(env->GetPrimitiveArrayCritical(valuesArray, NULL));
uint32_t index = 0;
do {
uint32_t axis = bits.clearFirstMarkedBit();
- outRawPointerCoords->setAxisValue(axis, values[index++]);
+ out.setAxisValue(axis, values[index++]);
} while (!bits.isEmpty());
env->ReleasePrimitiveArrayCritical(valuesArray, values, JNI_ABORT);
env->DeleteLocalRef(valuesArray);
}
}
+ return out;
}
static jfloatArray obtainPackedAxisValuesArray(JNIEnv* env, uint32_t minSize,
@@ -303,14 +300,13 @@
env->SetLongField(outPointerCoordsObj, gPointerCoordsClassInfo.mPackedAxisBits, outBits);
}
-static void pointerPropertiesToNative(JNIEnv* env, jobject pointerPropertiesObj,
- PointerProperties* outPointerProperties) {
- outPointerProperties->clear();
- outPointerProperties->id = env->GetIntField(pointerPropertiesObj,
- gPointerPropertiesClassInfo.id);
- const int32_t toolType = env->GetIntField(pointerPropertiesObj,
- gPointerPropertiesClassInfo.toolType);
- outPointerProperties->toolType = static_cast<ToolType>(toolType);
+static PointerProperties pointerPropertiesToNative(JNIEnv* env, jobject pointerPropertiesObj) {
+ PointerProperties out{};
+ out.id = env->GetIntField(pointerPropertiesObj, gPointerPropertiesClassInfo.id);
+ const int32_t toolType =
+ env->GetIntField(pointerPropertiesObj, gPointerPropertiesClassInfo.toolType);
+ out.toolType = static_cast<ToolType>(toolType);
+ return out;
}
static void pointerPropertiesFromNative(JNIEnv* env, const PointerProperties* pointerProperties,
@@ -343,15 +339,21 @@
event = std::make_unique<MotionEvent>();
}
- PointerProperties pointerProperties[pointerCount];
- PointerCoords rawPointerCoords[pointerCount];
+ ui::Transform transform;
+ transform.set(xOffset, yOffset);
+ const ui::Transform inverseTransform = transform.inverse();
+
+ std::vector<PointerProperties> pointerProperties;
+ pointerProperties.reserve(pointerCount);
+ std::vector<PointerCoords> rawPointerCoords;
+ rawPointerCoords.reserve(pointerCount);
for (jint i = 0; i < pointerCount; i++) {
jobject pointerPropertiesObj = env->GetObjectArrayElement(pointerPropertiesObjArray, i);
if (!pointerPropertiesObj) {
return 0;
}
- pointerPropertiesToNative(env, pointerPropertiesObj, &pointerProperties[i]);
+ pointerProperties.emplace_back(pointerPropertiesToNative(env, pointerPropertiesObj));
env->DeleteLocalRef(pointerPropertiesObj);
jobject pointerCoordsObj = env->GetObjectArrayElement(pointerCoordsObjArray, i);
@@ -359,19 +361,24 @@
jniThrowNullPointerException(env, "pointerCoords");
return 0;
}
- pointerCoordsToNative(env, pointerCoordsObj, xOffset, yOffset, &rawPointerCoords[i]);
+ rawPointerCoords.emplace_back(pointerCoordsToNative(env, pointerCoordsObj));
+ PointerCoords& coords = rawPointerCoords.back();
+ if (coords.getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION) != 0.f) {
+ flags |= AMOTION_EVENT_PRIVATE_FLAG_SUPPORTS_ORIENTATION |
+ AMOTION_EVENT_PRIVATE_FLAG_SUPPORTS_DIRECTIONAL_ORIENTATION;
+ }
+ MotionEvent::calculateTransformedCoordsInPlace(coords, source, flags, inverseTransform);
env->DeleteLocalRef(pointerCoordsObj);
}
- ui::Transform transform;
- transform.set(xOffset, yOffset);
- ui::Transform identityTransform;
+ static const ui::Transform kIdentityTransform;
event->initialize(InputEvent::nextId(), deviceId, source, ui::LogicalDisplayId{displayId},
INVALID_HMAC, action, 0, flags, edgeFlags, metaState, buttonState,
static_cast<MotionClassification>(classification), transform, xPrecision,
yPrecision, AMOTION_EVENT_INVALID_CURSOR_POSITION,
- AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, downTimeNanos,
- eventTimeNanos, pointerCount, pointerProperties, rawPointerCoords);
+ AMOTION_EVENT_INVALID_CURSOR_POSITION, kIdentityTransform, downTimeNanos,
+ eventTimeNanos, pointerCount, pointerProperties.data(),
+ rawPointerCoords.data());
return reinterpret_cast<jlong>(event.release());
}
@@ -391,7 +398,10 @@
return;
}
- PointerCoords rawPointerCoords[pointerCount];
+ const ui::Transform inverseTransform = event->getTransform().inverse();
+
+ std::vector<PointerCoords> rawPointerCoords;
+ rawPointerCoords.reserve(pointerCount);
for (size_t i = 0; i < pointerCount; i++) {
jobject pointerCoordsObj = env->GetObjectArrayElement(pointerCoordsObjArray, i);
@@ -399,12 +409,13 @@
jniThrowNullPointerException(env, "pointerCoords");
return;
}
- pointerCoordsToNative(env, pointerCoordsObj, event->getRawXOffset(), event->getRawYOffset(),
- &rawPointerCoords[i]);
+ rawPointerCoords.emplace_back(pointerCoordsToNative(env, pointerCoordsObj));
+ MotionEvent::calculateTransformedCoordsInPlace(rawPointerCoords.back(), event->getSource(),
+ event->getFlags(), inverseTransform);
env->DeleteLocalRef(pointerCoordsObj);
}
- event->addSample(eventTimeNanos, rawPointerCoords);
+ event->addSample(eventTimeNanos, rawPointerCoords.data());
event->setMetaState(event->getMetaState() | metaState);
}
@@ -685,13 +696,15 @@
static jint android_view_MotionEvent_nativeGetFlags(CRITICAL_JNI_PARAMS_COMMA jlong nativePtr) {
MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
- return event->getFlags();
+ // Prevent private flags from being used in Java.
+ return event->getFlags() & ~AMOTION_EVENT_PRIVATE_FLAG_MASK;
}
static void android_view_MotionEvent_nativeSetFlags(CRITICAL_JNI_PARAMS_COMMA jlong nativePtr,
jint flags) {
MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
- event->setFlags(flags);
+ // Prevent private flags from being used from Java.
+ event->setFlags(flags & ~AMOTION_EVENT_PRIVATE_FLAG_MASK);
}
static jint android_view_MotionEvent_nativeGetEdgeFlags(CRITICAL_JNI_PARAMS_COMMA jlong nativePtr) {
diff --git a/core/res/res/drawable/floating_popup_background_dark.xml b/core/res/res/drawable/floating_popup_background.xml
similarity index 84%
rename from core/res/res/drawable/floating_popup_background_dark.xml
rename to core/res/res/drawable/floating_popup_background.xml
index c4b4448..99acedf 100644
--- a/core/res/res/drawable/floating_popup_background_dark.xml
+++ b/core/res/res/drawable/floating_popup_background.xml
@@ -16,8 +16,9 @@
*/
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:shape="rectangle">
- <solid android:color="@color/background_floating_material_dark" />
+ <solid android:color="?androidprv:attr/materialColorSurfaceContainerHighest"/>
<corners android:radius="?android:attr/dialogCornerRadius" />
</shape>
diff --git a/core/res/res/drawable/floating_popup_background_light.xml b/core/res/res/drawable/floating_popup_background_light.xml
deleted file mode 100644
index 767140d..0000000
--- a/core/res/res/drawable/floating_popup_background_light.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/* Copyright 2015, 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.
-*/
--->
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
- android:shape="rectangle">
- <solid android:color="@color/background_floating_material_light" />
- <corners android:radius="?android:attr/dialogCornerRadius" />
-</shape>
-
diff --git a/core/res/res/layout/floating_popup_container.xml b/core/res/res/layout/floating_popup_container.xml
index 776a35d..96f0909 100644
--- a/core/res/res/layout/floating_popup_container.xml
+++ b/core/res/res/layout/floating_popup_container.xml
@@ -24,4 +24,4 @@
android:elevation="@android:dimen/text_edit_floating_toolbar_elevation"
android:focusable="true"
android:focusableInTouchMode="true"
- android:background="?attr/floatingToolbarPopupBackgroundDrawable"/>
+ android:background="@drawable/floating_popup_background"/>
diff --git a/core/res/res/layout/floating_popup_menu_button.xml b/core/res/res/layout/floating_popup_menu_button.xml
index e4c2a34..0b3861c 100644
--- a/core/res/res/layout/floating_popup_menu_button.xml
+++ b/core/res/res/layout/floating_popup_menu_button.xml
@@ -16,6 +16,7 @@
*/
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
@@ -53,7 +54,7 @@
android:ellipsize="end"
android:fontFamily="@*android:string/config_bodyFontFamily"
android:textSize="@dimen/floating_toolbar_text_size"
- android:textColor="?attr/floatingToolbarForegroundColor"
+ android:textColor="?androidprv:attr/materialColorOnSurface"
android:background="@null"
android:focusable="false"
android:focusableInTouchMode="false"
diff --git a/core/res/res/layout/floating_popup_overflow_button.xml b/core/res/res/layout/floating_popup_overflow_button.xml
index 12e2000..a51836b 100644
--- a/core/res/res/layout/floating_popup_overflow_button.xml
+++ b/core/res/res/layout/floating_popup_overflow_button.xml
@@ -16,6 +16,7 @@
*/
-->
<ImageButton xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:id="@+id/overflow"
android:layout_width="@dimen/floating_toolbar_menu_image_button_width"
android:layout_height="@dimen/floating_toolbar_height"
@@ -25,4 +26,4 @@
android:paddingBottom="@dimen/floating_toolbar_menu_image_button_vertical_padding"
android:scaleType="centerInside"
android:background="?attr/actionBarItemBackground"
- android:tint="?attr/floatingToolbarForegroundColor" />
+ android:tint="?androidprv:attr/materialColorOnSurface" />
diff --git a/core/res/res/layout/subscription_item_layout.xml b/core/res/res/layout/subscription_item_layout.xml
old mode 100755
new mode 100644
diff --git a/core/res/res/layout/text_edit_suggestion_container_material.xml b/core/res/res/layout/text_edit_suggestion_container_material.xml
index 34e7bc8..d6e1e9d 100644
--- a/core/res/res/layout/text_edit_suggestion_container_material.xml
+++ b/core/res/res/layout/text_edit_suggestion_container_material.xml
@@ -23,7 +23,7 @@
android:id="@+id/suggestionWindowContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:background="?android:attr/floatingToolbarPopupBackgroundDrawable"
+ android:background="@drawable/floating_popup_background"
android:elevation="@android:dimen/text_edit_floating_toolbar_elevation"
android:layout_margin="@android:dimen/text_edit_floating_toolbar_margin"
android:orientation="vertical"
diff --git a/core/res/res/values-af/donottranslate-cldr.xml b/core/res/res/values-af/donottranslate-cldr.xml
old mode 100755
new mode 100644
diff --git a/core/res/res/values-am/donottranslate-cldr.xml b/core/res/res/values-am/donottranslate-cldr.xml
old mode 100755
new mode 100644
diff --git a/core/res/res/values-ar-rEG/donottranslate-cldr.xml b/core/res/res/values-ar-rEG/donottranslate-cldr.xml
old mode 100755
new mode 100644
diff --git a/core/res/res/values-ar/donottranslate-cldr.xml b/core/res/res/values-ar/donottranslate-cldr.xml
old mode 100755
new mode 100644
diff --git a/core/res/res/values-bg/donottranslate-cldr.xml b/core/res/res/values-bg/donottranslate-cldr.xml
old mode 100755
new mode 100644
diff --git a/core/res/res/values-ca/donottranslate-cldr.xml b/core/res/res/values-ca/donottranslate-cldr.xml
old mode 100755
new mode 100644
diff --git a/core/res/res/values-cs/donottranslate-cldr.xml b/core/res/res/values-cs/donottranslate-cldr.xml
old mode 100755
new mode 100644
diff --git a/core/res/res/values-da/donottranslate-cldr.xml b/core/res/res/values-da/donottranslate-cldr.xml
old mode 100755
new mode 100644
diff --git a/core/res/res/values-de/donottranslate-cldr.xml b/core/res/res/values-de/donottranslate-cldr.xml
old mode 100755
new mode 100644
diff --git a/core/res/res/values-el/donottranslate-cldr.xml b/core/res/res/values-el/donottranslate-cldr.xml
old mode 100755
new mode 100644
diff --git a/core/res/res/values-en-rAU/donottranslate-cldr.xml b/core/res/res/values-en-rAU/donottranslate-cldr.xml
old mode 100755
new mode 100644
diff --git a/core/res/res/values-en-rCA/donottranslate-cldr.xml b/core/res/res/values-en-rCA/donottranslate-cldr.xml
old mode 100755
new mode 100644
diff --git a/core/res/res/values-en-rGB/donottranslate-cldr.xml b/core/res/res/values-en-rGB/donottranslate-cldr.xml
old mode 100755
new mode 100644
diff --git a/core/res/res/values-en-rIE/donottranslate-cldr.xml b/core/res/res/values-en-rIE/donottranslate-cldr.xml
old mode 100755
new mode 100644
diff --git a/core/res/res/values-en-rIN/donottranslate-cldr.xml b/core/res/res/values-en-rIN/donottranslate-cldr.xml
old mode 100755
new mode 100644
diff --git a/core/res/res/values-en-rNZ/donottranslate-cldr.xml b/core/res/res/values-en-rNZ/donottranslate-cldr.xml
old mode 100755
new mode 100644
diff --git a/core/res/res/values-en-rUS/donottranslate-cldr.xml b/core/res/res/values-en-rUS/donottranslate-cldr.xml
old mode 100755
new mode 100644
diff --git a/core/res/res/values-en-rZA/donottranslate-cldr.xml b/core/res/res/values-en-rZA/donottranslate-cldr.xml
old mode 100755
new mode 100644
diff --git a/core/res/res/values-es-rCO/donottranslate-cldr.xml b/core/res/res/values-es-rCO/donottranslate-cldr.xml
old mode 100755
new mode 100644
diff --git a/core/res/res/values-es-rCR/donottranslate-cldr.xml b/core/res/res/values-es-rCR/donottranslate-cldr.xml
old mode 100755
new mode 100644
diff --git a/core/res/res/values-es-rEC/donottranslate-cldr.xml b/core/res/res/values-es-rEC/donottranslate-cldr.xml
old mode 100755
new mode 100644
diff --git a/core/res/res/values-es-rGT/donottranslate-cldr.xml b/core/res/res/values-es-rGT/donottranslate-cldr.xml
old mode 100755
new mode 100644
diff --git a/core/res/res/values-es-rHN/donottranslate-cldr.xml b/core/res/res/values-es-rHN/donottranslate-cldr.xml
old mode 100755
new mode 100644
diff --git a/core/res/res/values-es-rMX/donottranslate-cldr.xml b/core/res/res/values-es-rMX/donottranslate-cldr.xml
old mode 100755
new mode 100644
diff --git a/core/res/res/values-es-rNI/donottranslate-cldr.xml b/core/res/res/values-es-rNI/donottranslate-cldr.xml
old mode 100755
new mode 100644
diff --git a/core/res/res/values-es-rPA/donottranslate-cldr.xml b/core/res/res/values-es-rPA/donottranslate-cldr.xml
old mode 100755
new mode 100644
diff --git a/core/res/res/values-es-rPE/donottranslate-cldr.xml b/core/res/res/values-es-rPE/donottranslate-cldr.xml
old mode 100755
new mode 100644
diff --git a/core/res/res/values-es-rSV/donottranslate-cldr.xml b/core/res/res/values-es-rSV/donottranslate-cldr.xml
old mode 100755
new mode 100644
diff --git a/core/res/res/values-es-rUS/donottranslate-cldr.xml b/core/res/res/values-es-rUS/donottranslate-cldr.xml
old mode 100755
new mode 100644
diff --git a/core/res/res/values-es/donottranslate-cldr.xml b/core/res/res/values-es/donottranslate-cldr.xml
old mode 100755
new mode 100644
diff --git a/core/res/res/values-fa/donottranslate-cldr.xml b/core/res/res/values-fa/donottranslate-cldr.xml
old mode 100755
new mode 100644
diff --git a/core/res/res/values-fi-rFI/donottranslate-cldr.xml b/core/res/res/values-fi-rFI/donottranslate-cldr.xml
old mode 100755
new mode 100644
diff --git a/core/res/res/values-fi/donottranslate-cldr.xml b/core/res/res/values-fi/donottranslate-cldr.xml
old mode 100755
new mode 100644
diff --git a/core/res/res/values-fr/donottranslate-cldr.xml b/core/res/res/values-fr/donottranslate-cldr.xml
old mode 100755
new mode 100644
diff --git a/core/res/res/values-hi-rIN/donottranslate-cldr.xml b/core/res/res/values-hi-rIN/donottranslate-cldr.xml
old mode 100755
new mode 100644
diff --git a/core/res/res/values-hi/donottranslate-cldr.xml b/core/res/res/values-hi/donottranslate-cldr.xml
old mode 100755
new mode 100644
diff --git a/core/res/res/values-hr-rHR/donottranslate-cldr.xml b/core/res/res/values-hr-rHR/donottranslate-cldr.xml
old mode 100755
new mode 100644
diff --git a/core/res/res/values-hr/donottranslate-cldr.xml b/core/res/res/values-hr/donottranslate-cldr.xml
old mode 100755
new mode 100644
diff --git a/core/res/res/values-hu-rHU/donottranslate-cldr.xml b/core/res/res/values-hu-rHU/donottranslate-cldr.xml
old mode 100755
new mode 100644
diff --git a/core/res/res/values-hu/donottranslate-cldr.xml b/core/res/res/values-hu/donottranslate-cldr.xml
old mode 100755
new mode 100644
diff --git a/core/res/res/values-in-rID/donottranslate-cldr.xml b/core/res/res/values-in-rID/donottranslate-cldr.xml
old mode 100755
new mode 100644
diff --git a/core/res/res/values-in/donottranslate-cldr.xml b/core/res/res/values-in/donottranslate-cldr.xml
old mode 100755
new mode 100644
diff --git a/core/res/res/values-it/donottranslate-cldr.xml b/core/res/res/values-it/donottranslate-cldr.xml
old mode 100755
new mode 100644
diff --git a/core/res/res/values-iw/donottranslate-cldr.xml b/core/res/res/values-iw/donottranslate-cldr.xml
old mode 100755
new mode 100644
diff --git a/core/res/res/values-ja/donottranslate-cldr.xml b/core/res/res/values-ja/donottranslate-cldr.xml
old mode 100755
new mode 100644
diff --git a/core/res/res/values-ko/donottranslate-cldr.xml b/core/res/res/values-ko/donottranslate-cldr.xml
old mode 100755
new mode 100644
diff --git a/core/res/res/values-lt-rLT/donottranslate-cldr.xml b/core/res/res/values-lt-rLT/donottranslate-cldr.xml
old mode 100755
new mode 100644
diff --git a/core/res/res/values-lt/donottranslate-cldr.xml b/core/res/res/values-lt/donottranslate-cldr.xml
old mode 100755
new mode 100644
diff --git a/core/res/res/values-lv-rLV/donottranslate-cldr.xml b/core/res/res/values-lv-rLV/donottranslate-cldr.xml
old mode 100755
new mode 100644
diff --git a/core/res/res/values-lv/donottranslate-cldr.xml b/core/res/res/values-lv/donottranslate-cldr.xml
old mode 100755
new mode 100644
diff --git a/core/res/res/values-mcc204-mnc04/config.xml b/core/res/res/values-mcc204-mnc04/config.xml
old mode 100755
new mode 100644
diff --git a/core/res/res/values-mcc310-mnc004/config.xml b/core/res/res/values-mcc310-mnc004/config.xml
old mode 100755
new mode 100644
diff --git a/core/res/res/values-mcc311-mnc480/config.xml b/core/res/res/values-mcc311-mnc480/config.xml
old mode 100755
new mode 100644
diff --git a/core/res/res/values-nb/donottranslate-cldr.xml b/core/res/res/values-nb/donottranslate-cldr.xml
old mode 100755
new mode 100644
diff --git a/core/res/res/values-nl/donottranslate-cldr.xml b/core/res/res/values-nl/donottranslate-cldr.xml
old mode 100755
new mode 100644
diff --git a/core/res/res/values-pl/donottranslate-cldr.xml b/core/res/res/values-pl/donottranslate-cldr.xml
old mode 100755
new mode 100644
diff --git a/core/res/res/values-pt-rPT/donottranslate-cldr.xml b/core/res/res/values-pt-rPT/donottranslate-cldr.xml
old mode 100755
new mode 100644
diff --git a/core/res/res/values-pt/donottranslate-cldr.xml b/core/res/res/values-pt/donottranslate-cldr.xml
old mode 100755
new mode 100644
diff --git a/core/res/res/values-ro-rRO/donottranslate-cldr.xml b/core/res/res/values-ro-rRO/donottranslate-cldr.xml
old mode 100755
new mode 100644
diff --git a/core/res/res/values-ro/donottranslate-cldr.xml b/core/res/res/values-ro/donottranslate-cldr.xml
old mode 100755
new mode 100644
diff --git a/core/res/res/values-ru/donottranslate-cldr.xml b/core/res/res/values-ru/donottranslate-cldr.xml
old mode 100755
new mode 100644
diff --git a/core/res/res/values-sk-rSK/donottranslate-cldr.xml b/core/res/res/values-sk-rSK/donottranslate-cldr.xml
old mode 100755
new mode 100644
diff --git a/core/res/res/values-sk/donottranslate-cldr.xml b/core/res/res/values-sk/donottranslate-cldr.xml
old mode 100755
new mode 100644
diff --git a/core/res/res/values-sl-rSI/donottranslate-cldr.xml b/core/res/res/values-sl-rSI/donottranslate-cldr.xml
old mode 100755
new mode 100644
diff --git a/core/res/res/values-sl/donottranslate-cldr.xml b/core/res/res/values-sl/donottranslate-cldr.xml
old mode 100755
new mode 100644
diff --git a/core/res/res/values-sr-rRS/donottranslate-cldr.xml b/core/res/res/values-sr-rRS/donottranslate-cldr.xml
old mode 100755
new mode 100644
diff --git a/core/res/res/values-sr/donottranslate-cldr.xml b/core/res/res/values-sr/donottranslate-cldr.xml
old mode 100755
new mode 100644
diff --git a/core/res/res/values-sv/donottranslate-cldr.xml b/core/res/res/values-sv/donottranslate-cldr.xml
old mode 100755
new mode 100644
diff --git a/core/res/res/values-sw/donottranslate-cldr.xml b/core/res/res/values-sw/donottranslate-cldr.xml
old mode 100755
new mode 100644
diff --git a/core/res/res/values-th-rTH/donottranslate-cldr.xml b/core/res/res/values-th-rTH/donottranslate-cldr.xml
old mode 100755
new mode 100644
diff --git a/core/res/res/values-th/donottranslate-cldr.xml b/core/res/res/values-th/donottranslate-cldr.xml
old mode 100755
new mode 100644
diff --git a/core/res/res/values-tl/donottranslate-cldr.xml b/core/res/res/values-tl/donottranslate-cldr.xml
old mode 100755
new mode 100644
diff --git a/core/res/res/values-tr/donottranslate-cldr.xml b/core/res/res/values-tr/donottranslate-cldr.xml
old mode 100755
new mode 100644
diff --git a/core/res/res/values-uk-rUA/donottranslate-cldr.xml b/core/res/res/values-uk-rUA/donottranslate-cldr.xml
old mode 100755
new mode 100644
diff --git a/core/res/res/values-uk/donottranslate-cldr.xml b/core/res/res/values-uk/donottranslate-cldr.xml
old mode 100755
new mode 100644
diff --git a/core/res/res/values-vi-rVN/donottranslate-cldr.xml b/core/res/res/values-vi-rVN/donottranslate-cldr.xml
old mode 100755
new mode 100644
diff --git a/core/res/res/values-vi/donottranslate-cldr.xml b/core/res/res/values-vi/donottranslate-cldr.xml
old mode 100755
new mode 100644
diff --git a/core/res/res/values-zh-rCN/donottranslate-cldr.xml b/core/res/res/values-zh-rCN/donottranslate-cldr.xml
old mode 100755
new mode 100644
diff --git a/core/res/res/values-zh-rTW/donottranslate-cldr.xml b/core/res/res/values-zh-rTW/donottranslate-cldr.xml
old mode 100755
new mode 100644
diff --git a/core/res/res/values-zu/donottranslate-cldr.xml b/core/res/res/values-zu/donottranslate-cldr.xml
old mode 100755
new mode 100644
diff --git a/core/res/res/values/arrays.xml b/core/res/res/values/arrays.xml
index 575573c..df5cbb1 100644
--- a/core/res/res/values/arrays.xml
+++ b/core/res/res/values/arrays.xml
@@ -37,8 +37,7 @@
<item>@drawable/fastscroll_label_right_material</item>
<item>@drawable/fastscroll_thumb_material</item>
<item>@drawable/fastscroll_track_material</item>
- <item>@drawable/floating_popup_background_dark</item>
- <item>@drawable/floating_popup_background_light</item>
+ <item>@drawable/floating_popup_background</item>
<item>@drawable/ic_ab_back_material</item>
<item>@drawable/ic_ab_back_material_dark</item>
<item>@drawable/ic_ab_back_material_light</item>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index c74bc9b..9846b71 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -606,11 +606,9 @@
<!-- ============ -->
<eat-comment />
<attr name="floatingToolbarCloseDrawable" format="reference" />
- <attr name="floatingToolbarForegroundColor" format="reference|color" />
<attr name="floatingToolbarItemBackgroundBorderlessDrawable" format="reference" />
<attr name="floatingToolbarItemBackgroundDrawable" format="reference" />
<attr name="floatingToolbarOpenDrawable" format="reference" />
- <attr name="floatingToolbarPopupBackgroundDrawable" format="reference" />
<attr name="floatingToolbarDividerColor" format="reference" />
<!-- ============ -->
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 4dfe000..f43351a 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -7076,4 +7076,8 @@
<!-- Whether the system uses auto-suspend mode. -->
<bool name="config_useAutoSuspend">true</bool>
+
+ <!-- Whether to show GAIA education screen during account login of private space setup.
+ OEM/Partner can explicitly opt to disable the screen. -->
+ <bool name="config_enableGaiaEducationInPrivateSpace">true</bool>
</resources>
diff --git a/core/res/res/values/donottranslate-cldr.xml b/core/res/res/values/donottranslate-cldr.xml
old mode 100755
new mode 100644
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index cc74d02..639b746 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -521,6 +521,7 @@
<java-symbol type="bool" name="config_preferKeepClearForFocus" />
<java-symbol type="bool" name="config_hibernationDeletesOatArtifactsEnabled"/>
<java-symbol type="integer" name="config_defaultAnalogClockSecondsHandFps"/>
+ <java-symbol type="bool" name="config_enableGaiaEducationInPrivateSpace"/>
<java-symbol type="color" name="tab_indicator_text_v4" />
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index bdbf96b..c3d304d 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -391,11 +391,9 @@
<!-- Floating toolbar styles -->
<item name="floatingToolbarCloseDrawable">@drawable/ic_ab_back_material_dark</item>
- <item name="floatingToolbarForegroundColor">@color/foreground_material_dark</item>
<item name="floatingToolbarItemBackgroundBorderlessDrawable">@drawable/item_background_borderless_material_dark</item>
<item name="floatingToolbarItemBackgroundDrawable">@drawable/item_background_material_dark</item>
<item name="floatingToolbarOpenDrawable">@drawable/ic_menu_moreoverflow_material_dark</item>
- <item name="floatingToolbarPopupBackgroundDrawable">@drawable/floating_popup_background_dark</item>
<item name="floatingToolbarDividerColor">@color/floating_popup_divider_dark</item>
<!-- SearchView attributes -->
@@ -579,11 +577,9 @@
<!-- Floating toolbar styles -->
<item name="floatingToolbarCloseDrawable">@drawable/ic_ab_back_material_light</item>
- <item name="floatingToolbarForegroundColor">@color/foreground_material_light</item>
<item name="floatingToolbarItemBackgroundBorderlessDrawable">@drawable/item_background_borderless_material_light</item>
<item name="floatingToolbarItemBackgroundDrawable">@drawable/item_background_material_light</item>
<item name="floatingToolbarOpenDrawable">@drawable/ic_menu_moreoverflow_material_light</item>
- <item name="floatingToolbarPopupBackgroundDrawable">@drawable/floating_popup_background_light</item>
<item name="floatingToolbarDividerColor">@color/floating_popup_divider_light</item>
<!-- Tooltip popup colors -->
diff --git a/core/sysprop/Android.bp b/core/sysprop/Android.bp
index 512a2eb..ed82765 100644
--- a/core/sysprop/Android.bp
+++ b/core/sysprop/Android.bp
@@ -43,3 +43,10 @@
property_owner: "Platform",
api_packages: ["android.sysprop"],
}
+
+sysprop_library {
+ name: "com.android.sysprop.view",
+ srcs: ["ViewProperties.sysprop"],
+ property_owner: "Platform",
+ api_packages: ["android.sysprop"],
+}
diff --git a/core/sysprop/ViewProperties.sysprop b/core/sysprop/ViewProperties.sysprop
new file mode 100644
index 0000000..e801643
--- /dev/null
+++ b/core/sysprop/ViewProperties.sysprop
@@ -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.
+
+module: "android.sysprop.ViewProperties"
+owner: Platform
+
+# On low-end devices, the cost of calculating frame rate can
+# have noticeable overhead. These devices don't benefit from
+# reduced frame rate as much as they benefit from reduced
+# work. By setting this to false, the device won't do any
+# VRR frame rate calculation for Views.
+prop {
+ api_name: "vrr_enabled"
+ type: Boolean
+ prop_name: "ro.view.vrr.enabled"
+ scope: Internal
+ access: Readonly
+}
diff --git a/core/tests/BroadcastRadioTests/src/android/hardware/radio/RadioManagerTest.java b/core/tests/BroadcastRadioTests/src/android/hardware/radio/RadioManagerTest.java
index 4f9b269..4c3d4e3 100644
--- a/core/tests/BroadcastRadioTests/src/android/hardware/radio/RadioManagerTest.java
+++ b/core/tests/BroadcastRadioTests/src/android/hardware/radio/RadioManagerTest.java
@@ -16,8 +16,6 @@
package android.hardware.radio;
-import static com.google.common.truth.Truth.assertWithMessage;
-
import static org.junit.Assert.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
@@ -36,6 +34,8 @@
import android.platform.test.flag.junit.SetFlagsRule;
import android.util.ArrayMap;
+import com.google.common.truth.Expect;
+
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -155,6 +155,9 @@
private RadioManager mRadioManager;
private final ApplicationInfo mApplicationInfo = new ApplicationInfo();
+ @Rule
+ public final Expect mExpect = Expect.create();
+
@Mock
private IRadioService mRadioServiceMock;
@Mock
@@ -175,7 +178,7 @@
() -> new RadioManager.AmBandDescriptor(REGION, /* type= */ 100, AM_LOWER_LIMIT,
AM_UPPER_LIMIT, AM_SPACING, STEREO_SUPPORTED));
- assertWithMessage("Unsupported band type exception")
+ mExpect.withMessage("Unsupported band type exception")
.that(thrown).hasMessageThat().contains("Unsupported band");
}
@@ -183,7 +186,7 @@
public void getType_forBandDescriptor() {
RadioManager.BandDescriptor bandDescriptor = createAmBandDescriptor();
- assertWithMessage("AM Band Descriptor type")
+ mExpect.withMessage("AM Band Descriptor type")
.that(bandDescriptor.getType()).isEqualTo(RadioManager.BAND_AM);
}
@@ -191,7 +194,7 @@
public void getRegion_forBandDescriptor() {
RadioManager.BandDescriptor bandDescriptor = createFmBandDescriptor();
- assertWithMessage("FM Band Descriptor region")
+ mExpect.withMessage("FM Band Descriptor region")
.that(bandDescriptor.getRegion()).isEqualTo(REGION);
}
@@ -199,7 +202,7 @@
public void getLowerLimit_forBandDescriptor() {
RadioManager.BandDescriptor bandDescriptor = createFmBandDescriptor();
- assertWithMessage("FM Band Descriptor lower limit")
+ mExpect.withMessage("FM Band Descriptor lower limit")
.that(bandDescriptor.getLowerLimit()).isEqualTo(FM_LOWER_LIMIT);
}
@@ -207,7 +210,7 @@
public void getUpperLimit_forBandDescriptor() {
RadioManager.BandDescriptor bandDescriptor = createAmBandDescriptor();
- assertWithMessage("AM Band Descriptor upper limit")
+ mExpect.withMessage("AM Band Descriptor upper limit")
.that(bandDescriptor.getUpperLimit()).isEqualTo(AM_UPPER_LIMIT);
}
@@ -215,7 +218,7 @@
public void getSpacing_forBandDescriptor() {
RadioManager.BandDescriptor bandDescriptor = createAmBandDescriptor();
- assertWithMessage("AM Band Descriptor spacing")
+ mExpect.withMessage("AM Band Descriptor spacing")
.that(bandDescriptor.getSpacing()).isEqualTo(AM_SPACING);
}
@@ -223,7 +226,7 @@
public void describeContents_forBandDescriptor() {
RadioManager.BandDescriptor bandDescriptor = createFmBandDescriptor();
- assertWithMessage("Band Descriptor contents")
+ mExpect.withMessage("Band Descriptor contents")
.that(bandDescriptor.describeContents()).isEqualTo(0);
}
@@ -237,7 +240,7 @@
RadioManager.BandDescriptor bandDescriptorFromParcel =
RadioManager.BandDescriptor.CREATOR.createFromParcel(parcel);
- assertWithMessage("Band Descriptor created from parcel")
+ mExpect.withMessage("Band Descriptor created from parcel")
.that(bandDescriptorFromParcel).isEqualTo(bandDescriptor);
}
@@ -246,14 +249,14 @@
RadioManager.BandDescriptor[] bandDescriptors =
RadioManager.BandDescriptor.CREATOR.newArray(CREATOR_ARRAY_SIZE);
- assertWithMessage("Band Descriptors").that(bandDescriptors).hasLength(CREATOR_ARRAY_SIZE);
+ mExpect.withMessage("Band Descriptors").that(bandDescriptors).hasLength(CREATOR_ARRAY_SIZE);
}
@Test
public void isAmBand_forAmBandDescriptor_returnsTrue() {
RadioManager.BandDescriptor bandDescriptor = createAmBandDescriptor();
- assertWithMessage("Is AM Band Descriptor an AM band")
+ mExpect.withMessage("Is AM Band Descriptor an AM band")
.that(bandDescriptor.isAmBand()).isTrue();
}
@@ -261,43 +264,43 @@
public void isFmBand_forAmBandDescriptor_returnsFalse() {
RadioManager.BandDescriptor bandDescriptor = createAmBandDescriptor();
- assertWithMessage("Is AM Band Descriptor an FM band")
+ mExpect.withMessage("Is AM Band Descriptor an FM band")
.that(bandDescriptor.isFmBand()).isFalse();
}
@Test
public void isStereoSupported_forFmBandDescriptor() {
- assertWithMessage("FM Band Descriptor stereo")
+ mExpect.withMessage("FM Band Descriptor stereo")
.that(FM_BAND_DESCRIPTOR.isStereoSupported()).isEqualTo(STEREO_SUPPORTED);
}
@Test
public void isRdsSupported_forFmBandDescriptor() {
- assertWithMessage("FM Band Descriptor RDS or RBDS")
+ mExpect.withMessage("FM Band Descriptor RDS or RBDS")
.that(FM_BAND_DESCRIPTOR.isRdsSupported()).isEqualTo(RDS_SUPPORTED);
}
@Test
public void isTaSupported_forFmBandDescriptor() {
- assertWithMessage("FM Band Descriptor traffic announcement")
+ mExpect.withMessage("FM Band Descriptor traffic announcement")
.that(FM_BAND_DESCRIPTOR.isTaSupported()).isEqualTo(TA_SUPPORTED);
}
@Test
public void isAfSupported_forFmBandDescriptor() {
- assertWithMessage("FM Band Descriptor alternate frequency")
+ mExpect.withMessage("FM Band Descriptor alternate frequency")
.that(FM_BAND_DESCRIPTOR.isAfSupported()).isEqualTo(AF_SUPPORTED);
}
@Test
public void isEaSupported_forFmBandDescriptor() {
- assertWithMessage("FM Band Descriptor emergency announcement")
+ mExpect.withMessage("FM Band Descriptor emergency announcement")
.that(FM_BAND_DESCRIPTOR.isEaSupported()).isEqualTo(EA_SUPPORTED);
}
@Test
public void describeContents_forFmBandDescriptor() {
- assertWithMessage("FM Band Descriptor contents")
+ mExpect.withMessage("FM Band Descriptor contents")
.that(FM_BAND_DESCRIPTOR.describeContents()).isEqualTo(0);
}
@@ -310,7 +313,7 @@
RadioManager.FmBandDescriptor fmBandDescriptorFromParcel =
RadioManager.FmBandDescriptor.CREATOR.createFromParcel(parcel);
- assertWithMessage("FM Band Descriptor created from parcel")
+ mExpect.withMessage("FM Band Descriptor created from parcel")
.that(fmBandDescriptorFromParcel).isEqualTo(FM_BAND_DESCRIPTOR);
}
@@ -319,19 +322,19 @@
RadioManager.FmBandDescriptor[] fmBandDescriptors =
RadioManager.FmBandDescriptor.CREATOR.newArray(CREATOR_ARRAY_SIZE);
- assertWithMessage("FM Band Descriptors")
+ mExpect.withMessage("FM Band Descriptors")
.that(fmBandDescriptors).hasLength(CREATOR_ARRAY_SIZE);
}
@Test
public void isStereoSupported_forAmBandDescriptor() {
- assertWithMessage("AM Band Descriptor stereo")
+ mExpect.withMessage("AM Band Descriptor stereo")
.that(AM_BAND_DESCRIPTOR.isStereoSupported()).isEqualTo(STEREO_SUPPORTED);
}
@Test
public void describeContents_forAmBandDescriptor() {
- assertWithMessage("AM Band Descriptor contents")
+ mExpect.withMessage("AM Band Descriptor contents")
.that(AM_BAND_DESCRIPTOR.describeContents()).isEqualTo(0);
}
@@ -344,7 +347,7 @@
RadioManager.AmBandDescriptor amBandDescriptorFromParcel =
RadioManager.AmBandDescriptor.CREATOR.createFromParcel(parcel);
- assertWithMessage("FM Band Descriptor created from parcel")
+ mExpect.withMessage("FM Band Descriptor created from parcel")
.that(amBandDescriptorFromParcel).isEqualTo(AM_BAND_DESCRIPTOR);
}
@@ -353,7 +356,7 @@
RadioManager.AmBandDescriptor[] amBandDescriptors =
RadioManager.AmBandDescriptor.CREATOR.newArray(CREATOR_ARRAY_SIZE);
- assertWithMessage("AM Band Descriptors")
+ mExpect.withMessage("AM Band Descriptors")
.that(amBandDescriptors).hasLength(CREATOR_ARRAY_SIZE);
}
@@ -361,7 +364,7 @@
public void equals_withSameFmBandDescriptors_returnsTrue() {
RadioManager.FmBandDescriptor fmBandDescriptorCompared = createFmBandDescriptor();
- assertWithMessage("The same FM Band Descriptor")
+ mExpect.withMessage("The same FM Band Descriptor")
.that(FM_BAND_DESCRIPTOR).isEqualTo(fmBandDescriptorCompared);
}
@@ -369,19 +372,19 @@
public void equals_withSameAmBandDescriptors_returnsTrue() {
RadioManager.AmBandDescriptor amBandDescriptorCompared = createAmBandDescriptor();
- assertWithMessage("The same AM Band Descriptor")
+ mExpect.withMessage("The same AM Band Descriptor")
.that(AM_BAND_DESCRIPTOR).isEqualTo(amBandDescriptorCompared);
}
@Test
public void equals_withAmBandDescriptorsAndOtherTypeObject() {
- assertWithMessage("AM Band Descriptor")
+ mExpect.withMessage("AM Band Descriptor")
.that(AM_BAND_DESCRIPTOR).isNotEqualTo(FM_BAND_DESCRIPTOR);
}
@Test
public void equals_withFmBandDescriptorsAndOtherTypeObject() {
- assertWithMessage("FM Band Descriptor")
+ mExpect.withMessage("FM Band Descriptor")
.that(FM_BAND_DESCRIPTOR).isNotEqualTo(AM_BAND_DESCRIPTOR);
}
@@ -391,7 +394,7 @@
new RadioManager.AmBandDescriptor(REGION, RadioManager.BAND_AM, AM_LOWER_LIMIT,
AM_UPPER_LIMIT + AM_SPACING, AM_SPACING, STEREO_SUPPORTED);
- assertWithMessage("AM Band Descriptor of different upper limit")
+ mExpect.withMessage("AM Band Descriptor of different upper limit")
.that(AM_BAND_DESCRIPTOR).isNotEqualTo(amBandDescriptorCompared);
}
@@ -401,7 +404,7 @@
new RadioManager.AmBandDescriptor(REGION, RadioManager.BAND_AM, AM_LOWER_LIMIT,
AM_UPPER_LIMIT, AM_SPACING, !STEREO_SUPPORTED);
- assertWithMessage("AM Band Descriptor of different stereo support values")
+ mExpect.withMessage("AM Band Descriptor of different stereo support values")
.that(AM_BAND_DESCRIPTOR).isNotEqualTo(amBandDescriptorCompared);
}
@@ -411,7 +414,7 @@
REGION, RadioManager.BAND_FM, FM_LOWER_LIMIT, FM_UPPER_LIMIT, FM_SPACING * 2,
STEREO_SUPPORTED, RDS_SUPPORTED, TA_SUPPORTED, AF_SUPPORTED, EA_SUPPORTED);
- assertWithMessage("FM Band Descriptors of different support limit values")
+ mExpect.withMessage("FM Band Descriptors of different support limit values")
.that(FM_BAND_DESCRIPTOR).isNotEqualTo(fmBandDescriptorCompared);
}
@@ -421,7 +424,7 @@
REGION + 1, RadioManager.BAND_AM_HD, AM_LOWER_LIMIT, AM_UPPER_LIMIT, AM_SPACING,
STEREO_SUPPORTED, RDS_SUPPORTED, TA_SUPPORTED, AF_SUPPORTED, EA_SUPPORTED);
- assertWithMessage("FM Band Descriptors of different region values")
+ mExpect.withMessage("FM Band Descriptors of different region values")
.that(FM_BAND_DESCRIPTOR).isNotEqualTo(fmBandDescriptorCompared);
}
@@ -431,7 +434,7 @@
REGION, RadioManager.BAND_FM, FM_LOWER_LIMIT, FM_UPPER_LIMIT, FM_SPACING,
!STEREO_SUPPORTED, RDS_SUPPORTED, TA_SUPPORTED, AF_SUPPORTED, EA_SUPPORTED);
- assertWithMessage("FM Band Descriptors of different stereo support values")
+ mExpect.withMessage("FM Band Descriptors of different stereo support values")
.that(fmBandDescriptorCompared).isNotEqualTo(FM_BAND_DESCRIPTOR);
}
@@ -441,7 +444,7 @@
REGION, RadioManager.BAND_FM, FM_LOWER_LIMIT, FM_UPPER_LIMIT, FM_SPACING,
STEREO_SUPPORTED, !RDS_SUPPORTED, TA_SUPPORTED, AF_SUPPORTED, EA_SUPPORTED);
- assertWithMessage("FM Band Descriptors of different rds support values")
+ mExpect.withMessage("FM Band Descriptors of different rds support values")
.that(fmBandDescriptorCompared).isNotEqualTo(FM_BAND_DESCRIPTOR);
}
@@ -451,7 +454,7 @@
REGION, RadioManager.BAND_FM, FM_LOWER_LIMIT, FM_UPPER_LIMIT, FM_SPACING,
STEREO_SUPPORTED, RDS_SUPPORTED, !TA_SUPPORTED, AF_SUPPORTED, EA_SUPPORTED);
- assertWithMessage("FM Band Descriptors of different ta support values")
+ mExpect.withMessage("FM Band Descriptors of different ta support values")
.that(fmBandDescriptorCompared).isNotEqualTo(FM_BAND_DESCRIPTOR);
}
@@ -461,7 +464,7 @@
REGION, RadioManager.BAND_FM, FM_LOWER_LIMIT, FM_UPPER_LIMIT, FM_SPACING,
STEREO_SUPPORTED, RDS_SUPPORTED, TA_SUPPORTED, !AF_SUPPORTED, EA_SUPPORTED);
- assertWithMessage("FM Band Descriptors of different af support values")
+ mExpect.withMessage("FM Band Descriptors of different af support values")
.that(fmBandDescriptorCompared).isNotEqualTo(FM_BAND_DESCRIPTOR);
}
@@ -471,7 +474,7 @@
REGION, RadioManager.BAND_FM, FM_LOWER_LIMIT, FM_UPPER_LIMIT, FM_SPACING,
STEREO_SUPPORTED, RDS_SUPPORTED, TA_SUPPORTED, AF_SUPPORTED, !EA_SUPPORTED);
- assertWithMessage("FM Band Descriptors of different ea support values")
+ mExpect.withMessage("FM Band Descriptors of different ea support values")
.that(fmBandDescriptorCompared).isNotEqualTo(FM_BAND_DESCRIPTOR);
}
@@ -479,7 +482,7 @@
public void hashCode_withSameFmBandDescriptors_equals() {
RadioManager.FmBandDescriptor fmBandDescriptorCompared = createFmBandDescriptor();
- assertWithMessage("Hash code of the same FM Band Descriptor")
+ mExpect.withMessage("Hash code of the same FM Band Descriptor")
.that(fmBandDescriptorCompared.hashCode()).isEqualTo(FM_BAND_DESCRIPTOR.hashCode());
}
@@ -487,7 +490,7 @@
public void hashCode_withSameAmBandDescriptors_equals() {
RadioManager.AmBandDescriptor amBandDescriptorCompared = createAmBandDescriptor();
- assertWithMessage("Hash code of the same AM Band Descriptor")
+ mExpect.withMessage("Hash code of the same AM Band Descriptor")
.that(amBandDescriptorCompared.hashCode()).isEqualTo(AM_BAND_DESCRIPTOR.hashCode());
}
@@ -497,7 +500,7 @@
REGION, RadioManager.BAND_FM, FM_LOWER_LIMIT, FM_UPPER_LIMIT, FM_SPACING,
STEREO_SUPPORTED, RDS_SUPPORTED, TA_SUPPORTED, !AF_SUPPORTED, EA_SUPPORTED);
- assertWithMessage("Hash code of FM Band Descriptor of different spacing")
+ mExpect.withMessage("Hash code of FM Band Descriptor of different spacing")
.that(fmBandDescriptorCompared.hashCode())
.isNotEqualTo(FM_BAND_DESCRIPTOR.hashCode());
}
@@ -508,7 +511,7 @@
new RadioManager.AmBandDescriptor(REGION, RadioManager.BAND_AM, AM_LOWER_LIMIT,
AM_UPPER_LIMIT, AM_SPACING * 2, STEREO_SUPPORTED);
- assertWithMessage("Hash code of AM Band Descriptor of different spacing")
+ mExpect.withMessage("Hash code of AM Band Descriptor of different spacing")
.that(amBandDescriptorCompared.hashCode())
.isNotEqualTo(AM_BAND_DESCRIPTOR.hashCode());
}
@@ -517,7 +520,7 @@
public void getType_forBandConfig() {
RadioManager.BandConfig fmBandConfig = createFmBandConfig();
- assertWithMessage("FM Band Config type")
+ mExpect.withMessage("FM Band Config type")
.that(fmBandConfig.getType()).isEqualTo(RadioManager.BAND_FM);
}
@@ -525,7 +528,7 @@
public void getRegion_forBandConfig() {
RadioManager.BandConfig amBandConfig = createAmBandConfig();
- assertWithMessage("AM Band Config region")
+ mExpect.withMessage("AM Band Config region")
.that(amBandConfig.getRegion()).isEqualTo(REGION);
}
@@ -533,7 +536,7 @@
public void getLowerLimit_forBandConfig() {
RadioManager.BandConfig amBandConfig = createAmBandConfig();
- assertWithMessage("AM Band Config lower limit")
+ mExpect.withMessage("AM Band Config lower limit")
.that(amBandConfig.getLowerLimit()).isEqualTo(AM_LOWER_LIMIT);
}
@@ -541,7 +544,7 @@
public void getUpperLimit_forBandConfig() {
RadioManager.BandConfig fmBandConfig = createFmBandConfig();
- assertWithMessage("FM Band Config upper limit")
+ mExpect.withMessage("FM Band Config upper limit")
.that(fmBandConfig.getUpperLimit()).isEqualTo(FM_UPPER_LIMIT);
}
@@ -549,7 +552,7 @@
public void getSpacing_forBandConfig() {
RadioManager.BandConfig fmBandConfig = createFmBandConfig();
- assertWithMessage("FM Band Config spacing")
+ mExpect.withMessage("FM Band Config spacing")
.that(fmBandConfig.getSpacing()).isEqualTo(FM_SPACING);
}
@@ -557,7 +560,7 @@
public void describeContents_forBandConfig() {
RadioManager.BandConfig bandConfig = createFmBandConfig();
- assertWithMessage("FM Band Config contents")
+ mExpect.withMessage("FM Band Config contents")
.that(bandConfig.describeContents()).isEqualTo(0);
}
@@ -571,7 +574,7 @@
RadioManager.BandConfig bandConfigFromParcel =
RadioManager.BandConfig.CREATOR.createFromParcel(parcel);
- assertWithMessage("Band Config created from parcel")
+ mExpect.withMessage("Band Config created from parcel")
.that(bandConfigFromParcel).isEqualTo(bandConfig);
}
@@ -580,42 +583,42 @@
RadioManager.BandConfig[] bandConfigs =
RadioManager.BandConfig.CREATOR.newArray(CREATOR_ARRAY_SIZE);
- assertWithMessage("Band Configs").that(bandConfigs).hasLength(CREATOR_ARRAY_SIZE);
+ mExpect.withMessage("Band Configs").that(bandConfigs).hasLength(CREATOR_ARRAY_SIZE);
}
@Test
public void getStereo_forFmBandConfig() {
- assertWithMessage("FM Band Config stereo")
+ mExpect.withMessage("FM Band Config stereo")
.that(FM_BAND_CONFIG.getStereo()).isEqualTo(STEREO_SUPPORTED);
}
@Test
public void getRds_forFmBandConfig() {
- assertWithMessage("FM Band Config RDS or RBDS")
+ mExpect.withMessage("FM Band Config RDS or RBDS")
.that(FM_BAND_CONFIG.getRds()).isEqualTo(RDS_SUPPORTED);
}
@Test
public void getTa_forFmBandConfig() {
- assertWithMessage("FM Band Config traffic announcement")
+ mExpect.withMessage("FM Band Config traffic announcement")
.that(FM_BAND_CONFIG.getTa()).isEqualTo(TA_SUPPORTED);
}
@Test
public void getAf_forFmBandConfig() {
- assertWithMessage("FM Band Config alternate frequency")
+ mExpect.withMessage("FM Band Config alternate frequency")
.that(FM_BAND_CONFIG.getAf()).isEqualTo(AF_SUPPORTED);
}
@Test
public void getEa_forFmBandConfig() {
- assertWithMessage("FM Band Config emergency Announcement")
+ mExpect.withMessage("FM Band Config emergency Announcement")
.that(FM_BAND_CONFIG.getEa()).isEqualTo(EA_SUPPORTED);
}
@Test
public void describeContents_forFmBandConfig() {
- assertWithMessage("FM Band Config contents")
+ mExpect.withMessage("FM Band Config contents")
.that(FM_BAND_CONFIG.describeContents()).isEqualTo(0);
}
@@ -628,7 +631,7 @@
RadioManager.FmBandConfig fmBandConfigFromParcel =
RadioManager.FmBandConfig.CREATOR.createFromParcel(parcel);
- assertWithMessage("FM Band Config created from parcel")
+ mExpect.withMessage("FM Band Config created from parcel")
.that(fmBandConfigFromParcel).isEqualTo(FM_BAND_CONFIG);
}
@@ -637,18 +640,18 @@
RadioManager.FmBandConfig[] fmBandConfigs =
RadioManager.FmBandConfig.CREATOR.newArray(CREATOR_ARRAY_SIZE);
- assertWithMessage("FM Band Configs").that(fmBandConfigs).hasLength(CREATOR_ARRAY_SIZE);
+ mExpect.withMessage("FM Band Configs").that(fmBandConfigs).hasLength(CREATOR_ARRAY_SIZE);
}
@Test
public void getStereo_forAmBandConfig() {
- assertWithMessage("AM Band Config stereo")
+ mExpect.withMessage("AM Band Config stereo")
.that(AM_BAND_CONFIG.getStereo()).isEqualTo(STEREO_SUPPORTED);
}
@Test
public void describeContents_forAmBandConfig() {
- assertWithMessage("AM Band Config contents")
+ mExpect.withMessage("AM Band Config contents")
.that(AM_BAND_CONFIG.describeContents()).isEqualTo(0);
}
@@ -661,7 +664,7 @@
RadioManager.AmBandConfig amBandConfigFromParcel =
RadioManager.AmBandConfig.CREATOR.createFromParcel(parcel);
- assertWithMessage("AM Band Config created from parcel")
+ mExpect.withMessage("AM Band Config created from parcel")
.that(amBandConfigFromParcel).isEqualTo(AM_BAND_CONFIG);
}
@@ -670,7 +673,7 @@
RadioManager.AmBandConfig[] amBandConfigs =
RadioManager.AmBandConfig.CREATOR.newArray(CREATOR_ARRAY_SIZE);
- assertWithMessage("AM Band Configs").that(amBandConfigs).hasLength(CREATOR_ARRAY_SIZE);
+ mExpect.withMessage("AM Band Configs").that(amBandConfigs).hasLength(CREATOR_ARRAY_SIZE);
}
@Test
@@ -679,7 +682,7 @@
new RadioManager.FmBandConfig.Builder(FM_BAND_CONFIG);
RadioManager.FmBandConfig fmBandConfigCompared = builder.build();
- assertWithMessage("The same FM Band Config")
+ mExpect.withMessage("The same FM Band Config")
.that(FM_BAND_CONFIG).isEqualTo(fmBandConfigCompared);
}
@@ -690,7 +693,7 @@
AM_LOWER_LIMIT, AM_UPPER_LIMIT, AM_SPACING, STEREO_SUPPORTED, RDS_SUPPORTED,
TA_SUPPORTED, AF_SUPPORTED, EA_SUPPORTED));
- assertWithMessage("FM Band Config of different regions")
+ mExpect.withMessage("FM Band Config of different regions")
.that(FM_BAND_CONFIG).isNotEqualTo(fmBandConfigCompared);
}
@@ -701,7 +704,7 @@
FM_UPPER_LIMIT, FM_SPACING, !STEREO_SUPPORTED, RDS_SUPPORTED, TA_SUPPORTED,
AF_SUPPORTED, EA_SUPPORTED));
- assertWithMessage("FM Band Config with different stereo support values")
+ mExpect.withMessage("FM Band Config with different stereo support values")
.that(fmBandConfigCompared).isNotEqualTo(FM_BAND_CONFIG);
}
@@ -712,7 +715,7 @@
FM_UPPER_LIMIT, FM_SPACING, STEREO_SUPPORTED, !RDS_SUPPORTED, TA_SUPPORTED,
AF_SUPPORTED, EA_SUPPORTED));
- assertWithMessage("FM Band Config with different RDS support values")
+ mExpect.withMessage("FM Band Config with different RDS support values")
.that(fmBandConfigCompared).isNotEqualTo(FM_BAND_CONFIG);
}
@@ -723,7 +726,7 @@
FM_UPPER_LIMIT, FM_SPACING, STEREO_SUPPORTED, RDS_SUPPORTED, !TA_SUPPORTED,
AF_SUPPORTED, EA_SUPPORTED));
- assertWithMessage("FM Band Configs with different ta values")
+ mExpect.withMessage("FM Band Configs with different ta values")
.that(fmBandConfigCompared).isNotEqualTo(FM_BAND_CONFIG);
}
@@ -734,7 +737,7 @@
.setTa(TA_SUPPORTED).setAf(!AF_SUPPORTED).setEa(EA_SUPPORTED);
RadioManager.FmBandConfig fmBandConfigCompared = builder.build();
- assertWithMessage("FM Band Config of different af support value")
+ mExpect.withMessage("FM Band Config of different af support value")
.that(FM_BAND_CONFIG).isNotEqualTo(fmBandConfigCompared);
}
@@ -745,19 +748,19 @@
FM_UPPER_LIMIT, FM_SPACING, STEREO_SUPPORTED, RDS_SUPPORTED, TA_SUPPORTED,
AF_SUPPORTED, !EA_SUPPORTED));
- assertWithMessage("FM Band Configs with different ea support values")
+ mExpect.withMessage("FM Band Configs with different ea support values")
.that(fmBandConfigCompared).isNotEqualTo(FM_BAND_CONFIG);
}
@Test
public void equals_withAmBandConfigsAndOtherTypeObject() {
- assertWithMessage("AM Band Config")
+ mExpect.withMessage("AM Band Config")
.that(AM_BAND_CONFIG).isNotEqualTo(FM_BAND_CONFIG);
}
@Test
public void equals_withFmBandConfigsAndOtherTypeObject() {
- assertWithMessage("FM Band Config")
+ mExpect.withMessage("FM Band Config")
.that(FM_BAND_CONFIG).isNotEqualTo(AM_BAND_CONFIG);
}
@@ -767,7 +770,7 @@
new RadioManager.AmBandConfig.Builder(AM_BAND_CONFIG);
RadioManager.AmBandConfig amBandConfigCompared = builder.build();
- assertWithMessage("The same AM Band Config")
+ mExpect.withMessage("The same AM Band Config")
.that(AM_BAND_CONFIG).isEqualTo(amBandConfigCompared);
}
@@ -777,7 +780,7 @@
new RadioManager.AmBandDescriptor(REGION, RadioManager.BAND_AM_HD, AM_LOWER_LIMIT,
AM_UPPER_LIMIT, AM_SPACING, STEREO_SUPPORTED));
- assertWithMessage("AM Band Config of different type")
+ mExpect.withMessage("AM Band Config of different type")
.that(AM_BAND_CONFIG).isNotEqualTo(amBandConfigCompared);
}
@@ -787,7 +790,7 @@
createAmBandDescriptor()).setStereo(!STEREO_SUPPORTED);
RadioManager.AmBandConfig amBandConfigFromBuilder = builder.build();
- assertWithMessage("AM Band Config of different stereo value")
+ mExpect.withMessage("AM Band Config of different stereo value")
.that(AM_BAND_CONFIG).isNotEqualTo(amBandConfigFromBuilder);
}
@@ -795,7 +798,7 @@
public void hashCode_withSameFmBandConfigs_equals() {
RadioManager.FmBandConfig fmBandConfigCompared = createFmBandConfig();
- assertWithMessage("Hash code of the same FM Band Config")
+ mExpect.withMessage("Hash code of the same FM Band Config")
.that(FM_BAND_CONFIG.hashCode()).isEqualTo(fmBandConfigCompared.hashCode());
}
@@ -803,7 +806,7 @@
public void hashCode_withSameAmBandConfigs_equals() {
RadioManager.AmBandConfig amBandConfigCompared = createAmBandConfig();
- assertWithMessage("Hash code of the same AM Band Config")
+ mExpect.withMessage("Hash code of the same AM Band Config")
.that(amBandConfigCompared.hashCode()).isEqualTo(AM_BAND_CONFIG.hashCode());
}
@@ -814,7 +817,7 @@
FM_UPPER_LIMIT, FM_SPACING, STEREO_SUPPORTED, RDS_SUPPORTED, TA_SUPPORTED,
AF_SUPPORTED, EA_SUPPORTED));
- assertWithMessage("Hash code of FM Band Config with different type")
+ mExpect.withMessage("Hash code of FM Band Config with different type")
.that(fmBandConfigCompared.hashCode()).isNotEqualTo(FM_BAND_CONFIG.hashCode());
}
@@ -824,87 +827,87 @@
new RadioManager.AmBandDescriptor(REGION, RadioManager.BAND_AM, AM_LOWER_LIMIT,
AM_UPPER_LIMIT, AM_SPACING, !STEREO_SUPPORTED));
- assertWithMessage("Hash code of AM Band Config with different stereo support")
+ mExpect.withMessage("Hash code of AM Band Config with different stereo support")
.that(amBandConfigCompared.hashCode()).isNotEqualTo(AM_BAND_CONFIG.hashCode());
}
@Test
public void getId_forModuleProperties() {
- assertWithMessage("Properties id")
+ mExpect.withMessage("Properties id")
.that(AMFM_PROPERTIES.getId()).isEqualTo(PROPERTIES_ID);
}
@Test
public void getServiceName_forModuleProperties() {
- assertWithMessage("Properties service name")
+ mExpect.withMessage("Properties service name")
.that(AMFM_PROPERTIES.getServiceName()).isEqualTo(SERVICE_NAME);
}
@Test
public void getClassId_forModuleProperties() {
- assertWithMessage("Properties class ID")
+ mExpect.withMessage("Properties class ID")
.that(AMFM_PROPERTIES.getClassId()).isEqualTo(CLASS_ID);
}
@Test
public void getImplementor_forModuleProperties() {
- assertWithMessage("Properties implementor")
+ mExpect.withMessage("Properties implementor")
.that(AMFM_PROPERTIES.getImplementor()).isEqualTo(IMPLEMENTOR);
}
@Test
public void getProduct_forModuleProperties() {
- assertWithMessage("Properties product")
+ mExpect.withMessage("Properties product")
.that(AMFM_PROPERTIES.getProduct()).isEqualTo(PRODUCT);
}
@Test
public void getVersion_forModuleProperties() {
- assertWithMessage("Properties version")
+ mExpect.withMessage("Properties version")
.that(AMFM_PROPERTIES.getVersion()).isEqualTo(VERSION);
}
@Test
public void getSerial_forModuleProperties() {
- assertWithMessage("Serial properties")
+ mExpect.withMessage("Serial properties")
.that(AMFM_PROPERTIES.getSerial()).isEqualTo(SERIAL);
}
@Test
public void getNumTuners_forModuleProperties() {
- assertWithMessage("Number of tuners in properties")
+ mExpect.withMessage("Number of tuners in properties")
.that(AMFM_PROPERTIES.getNumTuners()).isEqualTo(NUM_TUNERS);
}
@Test
public void getNumAudioSources_forModuleProperties() {
- assertWithMessage("Number of audio sources in properties")
+ mExpect.withMessage("Number of audio sources in properties")
.that(AMFM_PROPERTIES.getNumAudioSources()).isEqualTo(NUM_AUDIO_SOURCES);
}
@Test
public void isInitializationRequired_forModuleProperties() {
- assertWithMessage("Initialization required in properties")
+ mExpect.withMessage("Initialization required in properties")
.that(AMFM_PROPERTIES.isInitializationRequired())
.isEqualTo(IS_INITIALIZATION_REQUIRED);
}
@Test
public void isCaptureSupported_forModuleProperties() {
- assertWithMessage("Capture support in properties")
+ mExpect.withMessage("Capture support in properties")
.that(AMFM_PROPERTIES.isCaptureSupported()).isEqualTo(IS_CAPTURE_SUPPORTED);
}
@Test
public void isBackgroundScanningSupported_forModuleProperties() {
- assertWithMessage("Background scan support in properties")
+ mExpect.withMessage("Background scan support in properties")
.that(AMFM_PROPERTIES.isBackgroundScanningSupported())
.isEqualTo(IS_BG_SCAN_SUPPORTED);
}
@Test
public void isProgramTypeSupported_withSupportedType_forModuleProperties() {
- assertWithMessage("AM/FM frequency type radio support in properties")
+ mExpect.withMessage("AM/FM frequency type radio support in properties")
.that(AMFM_PROPERTIES.isProgramTypeSupported(
ProgramSelector.IDENTIFIER_TYPE_AMFM_FREQUENCY))
.isTrue();
@@ -912,28 +915,28 @@
@Test
public void isProgramTypeSupported_withNonSupportedType_forModuleProperties() {
- assertWithMessage("DAB frequency type radio support in properties")
+ mExpect.withMessage("DAB frequency type radio support in properties")
.that(AMFM_PROPERTIES.isProgramTypeSupported(
ProgramSelector.IDENTIFIER_TYPE_DAB_FREQUENCY)).isFalse();
}
@Test
public void isProgramIdentifierSupported_withSupportedIdentifier_forModuleProperties() {
- assertWithMessage("AM/FM frequency identifier radio support in properties")
+ mExpect.withMessage("AM/FM frequency identifier radio support in properties")
.that(AMFM_PROPERTIES.isProgramIdentifierSupported(
ProgramSelector.IDENTIFIER_TYPE_AMFM_FREQUENCY)).isTrue();
}
@Test
public void isProgramIdentifierSupported_withNonSupportedIdentifier_forModuleProperties() {
- assertWithMessage("DAB frequency identifier radio support in properties")
+ mExpect.withMessage("DAB frequency identifier radio support in properties")
.that(AMFM_PROPERTIES.isProgramIdentifierSupported(
ProgramSelector.IDENTIFIER_TYPE_DAB_FREQUENCY)).isFalse();
}
@Test
public void getDabFrequencyTable_forModulePropertiesInitializedWithNullTable() {
- assertWithMessage("Properties DAB frequency table")
+ mExpect.withMessage("Properties DAB frequency table")
.that(AMFM_PROPERTIES.getDabFrequencyTable()).isNull();
}
@@ -941,32 +944,32 @@
public void getDabFrequencyTable_forModulePropertiesInitializedWithEmptyTable() {
RadioManager.ModuleProperties properties = createAmFmProperties(new ArrayMap<>());
- assertWithMessage("Properties DAB frequency table")
+ mExpect.withMessage("Properties DAB frequency table")
.that(properties.getDabFrequencyTable()).isNull();
}
@Test
public void getVendorInfo_forModuleProperties() {
- assertWithMessage("Properties vendor info")
+ mExpect.withMessage("Properties vendor info")
.that(AMFM_PROPERTIES.getVendorInfo()).isEmpty();
}
@Test
public void getBands_forModuleProperties() {
- assertWithMessage("Properties bands")
+ mExpect.withMessage("Properties bands")
.that(AMFM_PROPERTIES.getBands()).asList()
.containsExactly(AM_BAND_DESCRIPTOR, FM_BAND_DESCRIPTOR);
}
@Test
public void describeContents_forModuleProperties() {
- assertWithMessage("Module properties contents")
+ mExpect.withMessage("Module properties contents")
.that(AMFM_PROPERTIES.describeContents()).isEqualTo(0);
}
@Test
public void toString_forModuleProperties() {
- assertWithMessage("Module properties string").that(AMFM_PROPERTIES.toString())
+ mExpect.withMessage("Module properties string").that(AMFM_PROPERTIES.toString())
.contains(AM_BAND_DESCRIPTOR.toString() + ", " + FM_BAND_DESCRIPTOR.toString());
}
@@ -979,7 +982,7 @@
RadioManager.ModuleProperties modulePropertiesFromParcel =
RadioManager.ModuleProperties.CREATOR.createFromParcel(parcel);
- assertWithMessage("Module properties created from parcel")
+ mExpect.withMessage("Module properties created from parcel")
.that(modulePropertiesFromParcel).isEqualTo(AMFM_PROPERTIES);
}
@@ -994,7 +997,7 @@
RadioManager.ModuleProperties modulePropertiesFromParcel =
RadioManager.ModuleProperties.CREATOR.createFromParcel(parcel);
- assertWithMessage("Module properties created from parcel")
+ mExpect.withMessage("Module properties created from parcel")
.that(modulePropertiesFromParcel).isEqualTo(propertiesToParcel);
}
@@ -1003,7 +1006,7 @@
RadioManager.ModuleProperties propertiesCompared =
createAmFmProperties(/* dabFrequencyTable= */ null);
- assertWithMessage("The same module properties")
+ mExpect.withMessage("The same module properties")
.that(AMFM_PROPERTIES).isEqualTo(propertiesCompared);
}
@@ -1016,7 +1019,7 @@
SUPPORTED_PROGRAM_TYPES, SUPPORTED_IDENTIFIERS_TYPES, Map.of("5A", 174928),
/* vendorInfo= */ null);
- assertWithMessage("Module properties of different id")
+ mExpect.withMessage("Module properties of different id")
.that(AMFM_PROPERTIES).isNotEqualTo(propertiesDab);
}
@@ -1025,7 +1028,7 @@
RadioManager.ModuleProperties propertiesCompared =
createAmFmProperties(/* dabFrequencyTable= */ null);
- assertWithMessage("Hash code of the same module properties")
+ mExpect.withMessage("Hash code of the same module properties")
.that(propertiesCompared.hashCode()).isEqualTo(AMFM_PROPERTIES.hashCode());
}
@@ -1034,86 +1037,86 @@
RadioManager.ModuleProperties[] modulePropertiesArray =
RadioManager.ModuleProperties.CREATOR.newArray(CREATOR_ARRAY_SIZE);
- assertWithMessage("Module properties array")
+ mExpect.withMessage("Module properties array")
.that(modulePropertiesArray).hasLength(CREATOR_ARRAY_SIZE);
}
@Test
public void getSelector_forProgramInfo() {
- assertWithMessage("Selector of DAB program info")
+ mExpect.withMessage("Selector of DAB program info")
.that(DAB_PROGRAM_INFO.getSelector()).isEqualTo(DAB_SELECTOR);
}
@Test
public void getLogicallyTunedTo_forProgramInfo() {
- assertWithMessage("Identifier logically tuned to in DAB program info")
+ mExpect.withMessage("Identifier logically tuned to in DAB program info")
.that(DAB_PROGRAM_INFO.getLogicallyTunedTo()).isEqualTo(DAB_SID_EXT_IDENTIFIER);
}
@Test
public void getPhysicallyTunedTo_forProgramInfo() {
- assertWithMessage("Identifier physically tuned to DAB program info")
+ mExpect.withMessage("Identifier physically tuned to DAB program info")
.that(DAB_PROGRAM_INFO.getPhysicallyTunedTo()).isEqualTo(DAB_FREQUENCY_IDENTIFIER);
}
@Test
public void getRelatedContent_forProgramInfo() {
- assertWithMessage("DAB program info contents")
+ mExpect.withMessage("DAB program info contents")
.that(DAB_PROGRAM_INFO.getRelatedContent())
.containsExactly(DAB_SID_EXT_IDENTIFIER_RELATED);
}
@Test
public void getChannel_forProgramInfo() {
- assertWithMessage("Main channel of DAB program info")
+ mExpect.withMessage("Main channel of DAB program info")
.that(DAB_PROGRAM_INFO.getChannel()).isEqualTo(0);
}
@Test
public void getSubChannel_forProgramInfo() {
- assertWithMessage("Sub channel of DAB program info")
+ mExpect.withMessage("Sub channel of DAB program info")
.that(DAB_PROGRAM_INFO.getSubChannel()).isEqualTo(0);
}
@Test
public void isTuned_forProgramInfo() {
- assertWithMessage("Tuned status of DAB program info")
+ mExpect.withMessage("Tuned status of DAB program info")
.that(DAB_PROGRAM_INFO.isTuned()).isTrue();
}
@Test
public void isStereo_forProgramInfo() {
- assertWithMessage("Stereo support in DAB program info")
+ mExpect.withMessage("Stereo support in DAB program info")
.that(DAB_PROGRAM_INFO.isStereo()).isTrue();
}
@Test
public void isDigital_forProgramInfo() {
- assertWithMessage("Digital DAB program info")
+ mExpect.withMessage("Digital DAB program info")
.that(DAB_PROGRAM_INFO.isDigital()).isTrue();
}
@Test
public void isLive_forProgramInfo() {
- assertWithMessage("Live status of DAB program info")
+ mExpect.withMessage("Live status of DAB program info")
.that(DAB_PROGRAM_INFO.isLive()).isTrue();
}
@Test
public void isMuted_forProgramInfo() {
- assertWithMessage("Muted status of DAB program info")
+ mExpect.withMessage("Muted status of DAB program info")
.that(DAB_PROGRAM_INFO.isMuted()).isFalse();
}
@Test
public void isTrafficProgram_forProgramInfo() {
- assertWithMessage("Traffic program support in DAB program info")
+ mExpect.withMessage("Traffic program support in DAB program info")
.that(DAB_PROGRAM_INFO.isTrafficProgram()).isFalse();
}
@Test
public void isTrafficAnnouncementActive_forProgramInfo() {
- assertWithMessage("Active traffic announcement for DAB program info")
+ mExpect.withMessage("Active traffic announcement for DAB program info")
.that(DAB_PROGRAM_INFO.isTrafficAnnouncementActive()).isFalse();
}
@@ -1121,7 +1124,7 @@
public void isSignalAcquired_forProgramInfo() {
mSetFlagsRule.enableFlags(Flags.FLAG_HD_RADIO_IMPROVED);
- assertWithMessage("Signal acquisition status for HD program info")
+ mExpect.withMessage("Signal acquisition status for HD program info")
.that(HD_PROGRAM_INFO.isSignalAcquired()).isTrue();
}
@@ -1129,7 +1132,7 @@
public void isHdSisAvailable_forProgramInfo() {
mSetFlagsRule.enableFlags(Flags.FLAG_HD_RADIO_IMPROVED);
- assertWithMessage("SIS information acquisition status for HD program")
+ mExpect.withMessage("SIS information acquisition status for HD program")
.that(HD_PROGRAM_INFO.isHdSisAvailable()).isTrue();
}
@@ -1137,31 +1140,31 @@
public void isHdAudioAvailable_forProgramInfo() {
mSetFlagsRule.enableFlags(Flags.FLAG_HD_RADIO_IMPROVED);
- assertWithMessage("Audio acquisition status for HD program")
+ mExpect.withMessage("Audio acquisition status for HD program")
.that(HD_PROGRAM_INFO.isHdAudioAvailable()).isFalse();
}
@Test
public void getSignalStrength_forProgramInfo() {
- assertWithMessage("Signal strength of DAB program info")
+ mExpect.withMessage("Signal strength of DAB program info")
.that(DAB_PROGRAM_INFO.getSignalStrength()).isEqualTo(SIGNAL_QUALITY);
}
@Test
public void getMetadata_forProgramInfo() {
- assertWithMessage("Metadata of DAB program info")
+ mExpect.withMessage("Metadata of DAB program info")
.that(DAB_PROGRAM_INFO.getMetadata()).isEqualTo(METADATA);
}
@Test
public void getVendorInfo_forProgramInfo() {
- assertWithMessage("Vendor info of DAB program info")
+ mExpect.withMessage("Vendor info of DAB program info")
.that(DAB_PROGRAM_INFO.getVendorInfo()).isEmpty();
}
@Test
public void describeContents_forProgramInfo() {
- assertWithMessage("Program info contents")
+ mExpect.withMessage("Program info contents")
.that(DAB_PROGRAM_INFO.describeContents()).isEqualTo(0);
}
@@ -1170,7 +1173,7 @@
RadioManager.ProgramInfo[] programInfoArray =
RadioManager.ProgramInfo.CREATOR.newArray(CREATOR_ARRAY_SIZE);
- assertWithMessage("Program infos").that(programInfoArray).hasLength(CREATOR_ARRAY_SIZE);
+ mExpect.withMessage("Program infos").that(programInfoArray).hasLength(CREATOR_ARRAY_SIZE);
}
@Test
@@ -1182,7 +1185,7 @@
RadioManager.ProgramInfo programInfoFromParcel =
RadioManager.ProgramInfo.CREATOR.createFromParcel(parcel);
- assertWithMessage("Program info created from parcel")
+ mExpect.withMessage("Program info created from parcel")
.that(programInfoFromParcel).isEqualTo(DAB_PROGRAM_INFO);
}
@@ -1190,7 +1193,7 @@
public void equals_withSameProgramInfo_returnsTrue() {
RadioManager.ProgramInfo dabProgramInfoCompared = createDabProgramInfo(DAB_SELECTOR);
- assertWithMessage("The same program info")
+ mExpect.withMessage("The same program info")
.that(dabProgramInfoCompared).isEqualTo(DAB_PROGRAM_INFO);
}
@@ -1202,7 +1205,7 @@
/* vendorIds= */ null);
RadioManager.ProgramInfo dabProgramInfoCompared = createDabProgramInfo(dabSelectorCompared);
- assertWithMessage("Program info with different secondary id selectors")
+ mExpect.withMessage("Program info with different secondary id selectors")
.that(DAB_PROGRAM_INFO).isNotEqualTo(dabProgramInfoCompared);
}
@@ -1213,7 +1216,7 @@
mRadioManager.listModules(modules);
- assertWithMessage("Modules in radio manager")
+ mExpect.withMessage("Modules in radio manager")
.that(modules).containsExactly(AMFM_PROPERTIES);
}
@@ -1221,7 +1224,7 @@
public void listModules_forRadioManagerWithNullListAsInput_fails() throws Exception {
createRadioManager();
- assertWithMessage("Status when listing module with empty list input")
+ mExpect.withMessage("Status when listing module with empty list input")
.that(mRadioManager.listModules(null)).isEqualTo(RadioManager.STATUS_BAD_VALUE);
}
@@ -1231,7 +1234,7 @@
when(mRadioServiceMock.listModules()).thenReturn(null);
List<RadioManager.ModuleProperties> modules = new ArrayList<>();
- assertWithMessage("Status for listing module when getting null list from HAL client")
+ mExpect.withMessage("Status for listing module when getting null list from HAL client")
.that(mRadioManager.listModules(modules)).isEqualTo(RadioManager.STATUS_ERROR);
}
@@ -1241,7 +1244,7 @@
when(mRadioServiceMock.listModules()).thenThrow(new RemoteException());
List<RadioManager.ModuleProperties> modules = new ArrayList<>();
- assertWithMessage("Status for listing module when HAL client service is dead")
+ mExpect.withMessage("Status for listing module when HAL client service is dead")
.that(mRadioManager.listModules(modules))
.isEqualTo(RadioManager.STATUS_DEAD_OBJECT);
}
@@ -1267,7 +1270,21 @@
RadioTuner nullTuner = mRadioManager.openTuner(/* moduleId= */ 0, FM_BAND_CONFIG,
/* withAudio= */ true, mCallbackMock, /* handler= */ null);
- assertWithMessage("Radio tuner when service is dead").that(nullTuner).isNull();
+ mExpect.withMessage("Radio tuner when service is dead").that(nullTuner).isNull();
+ }
+
+ @Test
+ public void openTuner_withNullCallback() throws Exception {
+ createRadioManager();
+ int moduleId = 0;
+ boolean withAudio = true;
+
+ IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class,
+ () -> mRadioManager.openTuner(moduleId, FM_BAND_CONFIG, withAudio,
+ /* callback= */ null, /* handler= */ null));
+
+ mExpect.withMessage("Null tuner callback exception").that(thrown)
+ .hasMessageThat().contains("callback must not be empty");
}
@Test
@@ -1323,7 +1340,7 @@
RuntimeException thrown = assertThrows(RuntimeException.class,
() -> mRadioManager.addAnnouncementListener(enableTypeSet, mEventListener));
- assertWithMessage("Exception for adding announcement listener with dead service")
+ mExpect.withMessage("Exception for adding announcement listener with dead service")
.that(thrown).hasMessageThat().contains(exceptionMessage);
}
diff --git a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/AnnouncementAggregatorTest.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/AnnouncementAggregatorTest.java
index 0e0dbec..2bf0aa3 100644
--- a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/AnnouncementAggregatorTest.java
+++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/AnnouncementAggregatorTest.java
@@ -16,11 +16,11 @@
package com.android.server.broadcastradio.aidl;
-import static com.google.common.truth.Truth.assertWithMessage;
-
import static org.junit.Assert.assertThrows;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
@@ -33,7 +33,10 @@
import android.os.IBinder;
import android.os.RemoteException;
+import com.google.common.truth.Expect;
+
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
@@ -54,6 +57,9 @@
private AnnouncementAggregator mAnnouncementAggregator;
private IBinder.DeathRecipient mDeathRecipient;
+ @Rule
+ public final Expect mExpect = Expect.create();
+
@Mock
private IAnnouncementListener mListenerMock;
@Mock
@@ -75,6 +81,18 @@
}
@Test
+ public void constructor_withBinderDied() throws Exception {
+ RemoteException remoteException = new RemoteException("Binder is died");
+ doThrow(remoteException).when(mBinderMock).linkToDeath(any(), anyInt());
+
+ RuntimeException thrown = assertThrows(RuntimeException.class, () ->
+ new AnnouncementAggregator(mListenerMock, mLock));
+
+ mExpect.withMessage("Exception for dead binder").that(thrown).hasMessageThat()
+ .contains(remoteException.getMessage());
+ }
+
+ @Test
public void onListUpdated_withOneModuleWatcher() throws Exception {
ArgumentCaptor<IAnnouncementListener> moduleWatcherCaptor =
ArgumentCaptor.forClass(IAnnouncementListener.class);
@@ -103,7 +121,7 @@
moduleWatcherCaptor.getValue().onListUpdated(Arrays.asList(mAnnouncementMocks[index]));
verify(mListenerMock, times(index + 1)).onListUpdated(announcementsCaptor.capture());
- assertWithMessage("Number of announcements %s after %s announcements were updated",
+ mExpect.withMessage("Number of announcements %s after %s announcements were updated",
announcementsCaptor.getValue(), index + 1)
.that(announcementsCaptor.getValue().size()).isEqualTo(index + 1);
}
@@ -131,7 +149,7 @@
() -> mAnnouncementAggregator.watchModule(mRadioModuleMocks[0],
TEST_ENABLED_TYPES));
- assertWithMessage("Exception for watching module after aggregator has been closed")
+ mExpect.withMessage("Exception for watching module after aggregator has been closed")
.that(thrown).hasMessageThat()
.contains("announcement aggregator has already been closed");
}
diff --git a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/ConversionUtilsTest.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/ConversionUtilsTest.java
index 8d9fad9..42501c1 100644
--- a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/ConversionUtilsTest.java
+++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/ConversionUtilsTest.java
@@ -27,6 +27,7 @@
import android.hardware.broadcastradio.DabTableEntry;
import android.hardware.broadcastradio.IdentifierType;
import android.hardware.broadcastradio.Metadata;
+import android.hardware.broadcastradio.ProgramFilter;
import android.hardware.broadcastradio.ProgramIdentifier;
import android.hardware.broadcastradio.ProgramInfo;
import android.hardware.broadcastradio.Properties;
@@ -41,6 +42,7 @@
import android.hardware.radio.UniqueProgramIdentifier;
import android.os.ServiceSpecificException;
import android.platform.test.flag.junit.SetFlagsRule;
+import android.util.ArraySet;
import com.android.dx.mockito.inline.extended.StaticMockitoSessionBuilder;
import com.android.server.broadcastradio.ExtendedRadioMockitoTestCase;
@@ -93,6 +95,11 @@
private static final long TEST_HD_LOCATION_VALUE = 0x4E647007665CF6L;
private static final long TEST_VENDOR_ID_VALUE = 9_901;
+ private static final ProgramSelector.Identifier TEST_INVALID_ID =
+ new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_INVALID, 1);
+ private static final ProgramIdentifier TEST_HAL_INVALID_ID =
+ AidlTestUtils.makeHalIdentifier(IdentifierType.INVALID, 1);
+
private static final ProgramSelector.Identifier TEST_DAB_SID_EXT_ID =
new ProgramSelector.Identifier(
ProgramSelector.IDENTIFIER_TYPE_DAB_DMB_SID_EXT, TEST_DAB_DMB_SID_EXT_VALUE);
@@ -139,7 +146,7 @@
private static final int TEST_ANNOUNCEMENT_FREQUENCY = FM_LOWER_LIMIT + FM_SPACING;
private static final RadioManager.ModuleProperties MODULE_PROPERTIES =
- convertToModuleProperties();
+ createModuleProperties();
private static final Announcement ANNOUNCEMENT =
ConversionUtils.announcementFromHalAnnouncement(
AidlTestUtils.makeAnnouncement(TEST_ENABLED_TYPE, TEST_ANNOUNCEMENT_FREQUENCY));
@@ -291,6 +298,37 @@
}
@Test
+ public void propertiesFromHalProperties_withoutAmFmAndDabConfigs() {
+ RadioManager.ModuleProperties properties = createModuleProperties(/* amFmConfig= */ null,
+ new DabTableEntry[]{});
+
+ expect.withMessage("Empty AM/FM config")
+ .that(properties.getBands()).asList().isEmpty();
+ expect.withMessage("Empty DAB config")
+ .that(properties.getDabFrequencyTable()).isNull();
+ }
+
+ @Test
+ public void propertiesFromHalProperties_withInvalidBand() {
+ AmFmRegionConfig amFmRegionConfig = new AmFmRegionConfig();
+ amFmRegionConfig.ranges = new AmFmBandRange[]{createAmFmBandRange(/* lowerBound= */ 50000,
+ /* upperBound= */ 60000, /* spacing= */ 10),
+ createAmFmBandRange(FM_LOWER_LIMIT, FM_UPPER_LIMIT, FM_SPACING)};
+
+ RadioManager.ModuleProperties properties = createModuleProperties(amFmRegionConfig,
+ new DabTableEntry[]{});
+
+ RadioManager.BandDescriptor[] bands = properties.getBands();
+ expect.withMessage("Band descriptors").that(bands).hasLength(1);
+ expect.withMessage("FM band frequency lower limit")
+ .that(bands[0].getLowerLimit()).isEqualTo(FM_LOWER_LIMIT);
+ expect.withMessage("FM band frequency upper limit")
+ .that(bands[0].getUpperLimit()).isEqualTo(FM_UPPER_LIMIT);
+ expect.withMessage("FM band frequency spacing")
+ .that(bands[0].getSpacing()).isEqualTo(FM_SPACING);
+ }
+
+ @Test
public void identifierToHalProgramIdentifier_withDabId() {
ProgramIdentifier halDabId =
ConversionUtils.identifierToHalProgramIdentifier(TEST_DAB_SID_EXT_ID);
@@ -358,6 +396,13 @@
}
@Test
+ public void identifierFromHalProgramIdentifier_withInvalidIdentifier() {
+ expect.withMessage("Identifier converted from invalid HAL identifier")
+ .that(ConversionUtils.identifierFromHalProgramIdentifier(TEST_HAL_INVALID_ID))
+ .isNull();
+ }
+
+ @Test
public void programSelectorToHalProgramSelector_withValidSelector() {
android.hardware.broadcastradio.ProgramSelector halDabSelector =
ConversionUtils.programSelectorToHalProgramSelector(TEST_DAB_SELECTOR);
@@ -370,6 +415,23 @@
}
@Test
+ public void programSelectorToHalProgramSelector_withInvalidSecondaryId() {
+ ProgramSelector dabSelector = new ProgramSelector(ProgramSelector.PROGRAM_TYPE_DAB,
+ TEST_DAB_SID_EXT_ID, new ProgramSelector.Identifier[]{TEST_INVALID_ID,
+ TEST_DAB_FREQUENCY_ID, TEST_DAB_ENSEMBLE_ID}, /* vendorIds= */ null);
+
+ android.hardware.broadcastradio.ProgramSelector halDabSelector =
+ ConversionUtils.programSelectorToHalProgramSelector(dabSelector);
+
+ expect.withMessage("Primary identifier of converted HAL DAB selector with invalid "
+ + "secondary id").that(halDabSelector.primaryId)
+ .isEqualTo(TEST_HAL_DAB_SID_EXT_ID);
+ expect.withMessage("Secondary identifiers of converted HAL DAB selector with "
+ + "invalid secondary id").that(halDabSelector.secondaryIds).asList()
+ .containsExactly(TEST_HAL_DAB_FREQUENCY_ID, TEST_HAL_DAB_ENSEMBLE_ID);
+ }
+
+ @Test
public void programSelectorFromHalProgramSelector_withValidSelector() {
android.hardware.broadcastradio.ProgramSelector halDabSelector =
AidlTestUtils.makeHalSelector(TEST_HAL_DAB_SID_EXT_ID, new ProgramIdentifier[]{
@@ -386,6 +448,33 @@
}
@Test
+ public void programSelectorFromHalProgramSelector_withInvalidSelector() {
+ android.hardware.broadcastradio.ProgramSelector invalidSelector =
+ AidlTestUtils.makeHalSelector(TEST_HAL_INVALID_ID, new ProgramIdentifier[]{});
+
+ expect.withMessage("Selector converted from invalid HAL selector")
+ .that(ConversionUtils.programSelectorFromHalProgramSelector(invalidSelector))
+ .isNull();
+ }
+
+ @Test
+ public void programSelectorFromHalProgramSelector_withInvalidSecondaryId() {
+ android.hardware.broadcastradio.ProgramSelector halDabSelector =
+ AidlTestUtils.makeHalSelector(TEST_HAL_DAB_SID_EXT_ID, new ProgramIdentifier[]{
+ TEST_HAL_INVALID_ID, TEST_HAL_DAB_ENSEMBLE_ID, TEST_HAL_DAB_FREQUENCY_ID});
+
+ ProgramSelector dabSelector =
+ ConversionUtils.programSelectorFromHalProgramSelector(halDabSelector);
+
+ expect.withMessage("Primary identifier of converted DAB selector with invalid "
+ + "secondary id").that(dabSelector.getPrimaryId())
+ .isEqualTo(TEST_DAB_SID_EXT_ID);
+ expect.withMessage("Secondary identifiers of converted DAB selector with invalid "
+ + "secondary id").that(dabSelector.getSecondaryIds()).asList()
+ .containsExactly(TEST_DAB_FREQUENCY_ID, TEST_DAB_ENSEMBLE_ID);
+ }
+
+ @Test
public void programInfoFromHalProgramInfo_withValidProgramInfo() {
android.hardware.broadcastradio.ProgramSelector halDabSelector =
AidlTestUtils.makeHalSelector(TEST_HAL_DAB_SID_EXT_ID, new ProgramIdentifier[]{
@@ -622,11 +711,47 @@
.isEqualTo(TEST_ALBUM_ART);
}
- private static RadioManager.ModuleProperties convertToModuleProperties() {
+ @Test
+ public void getBands_withInvalidFrequency() {
+ expect.withMessage("Band for invalid frequency")
+ .that(Utils.getBand(/* freq= */ 110000)).isEqualTo(Utils.FrequencyBand.UNKNOWN);
+ }
+
+ @Test
+ public void filterToHalProgramFilter_withNullFilter() {
+ ProgramFilter filter = ConversionUtils.filterToHalProgramFilter(null);
+
+ expect.withMessage("Filter identifier types").that(filter.identifierTypes)
+ .asList().isEmpty();
+ expect.withMessage("Filter identifiers").that(filter.identifiers).asList()
+ .isEmpty();
+ }
+
+ @Test
+ public void filterToHalProgramFilter_withInvalidIdentifier() {
+ Set<ProgramSelector.Identifier> identifiers =
+ new ArraySet<ProgramSelector.Identifier>(2);
+ identifiers.add(TEST_INVALID_ID);
+ identifiers.add(TEST_DAB_SID_EXT_ID);
+ ProgramList.Filter filter = new ProgramList.Filter(/* identifierTypes */ new ArraySet<>(),
+ identifiers, /* includeCategories= */ true, /* excludeModifications= */ false);
+ ProgramFilter halFilter = ConversionUtils.filterToHalProgramFilter(filter);
+
+ expect.withMessage("Filter identifiers with invalid ones removed")
+ .that(halFilter.identifiers).asList().containsExactly(
+ ConversionUtils.identifierToHalProgramIdentifier(TEST_DAB_SID_EXT_ID));
+ }
+
+ private static RadioManager.ModuleProperties createModuleProperties() {
AmFmRegionConfig amFmConfig = createAmFmRegionConfig();
DabTableEntry[] dabTableEntries = new DabTableEntry[]{
createDabTableEntry(DAB_ENTRY_LABEL_1, DAB_ENTRY_FREQUENCY_1),
createDabTableEntry(DAB_ENTRY_LABEL_2, DAB_ENTRY_FREQUENCY_2)};
+ return createModuleProperties(amFmConfig, dabTableEntries);
+ }
+
+ private static RadioManager.ModuleProperties createModuleProperties(
+ AmFmRegionConfig amFmConfig, DabTableEntry[] dabTableEntries) {
Properties properties = createHalProperties();
return ConversionUtils.propertiesFromHalProperties(TEST_ID, TEST_SERVICE_NAME, properties,
diff --git a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/ProgramInfoCacheTest.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/ProgramInfoCacheTest.java
index ce27bc1..d64fcaf 100644
--- a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/ProgramInfoCacheTest.java
+++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/ProgramInfoCacheTest.java
@@ -440,6 +440,29 @@
TEST_DAB_UNIQUE_ID_ALTERNATIVE);
}
+ @Test
+ public void filterAndApplyChunkInternal_withInvalidProgramInfoAndIdentifiers()
+ throws RemoteException {
+ ProgramInfoCache cache = new ProgramInfoCache(/* filter= */ null,
+ /* complete= */ false, TEST_FM_INFO, TEST_RDS_INFO, TEST_DAB_INFO);
+ ProgramInfo[] halModified = new android.hardware.broadcastradio.ProgramInfo[1];
+ halModified[0] = AidlTestUtils.makeHalProgramInfo(
+ ConversionUtils.programSelectorToHalProgramSelector(TEST_DAB_SELECTOR_ALTERNATIVE),
+ ConversionUtils.identifierToHalProgramIdentifier(TEST_DAB_FREQUENCY_ID_ALTERNATIVE),
+ ConversionUtils.identifierToHalProgramIdentifier(TEST_DAB_FREQUENCY_ID_ALTERNATIVE),
+ TEST_SIGNAL_QUALITY);
+ ProgramIdentifier[] halRemoved = new android.hardware.broadcastradio.ProgramIdentifier[1];
+ halRemoved[0] = new android.hardware.broadcastradio.ProgramIdentifier();
+ ProgramListChunk halChunk = AidlTestUtils.makeHalChunk(/* purge= */ false,
+ /* complete= */ true, halModified, halRemoved);
+
+ List<ProgramList.Chunk> programListChunks = cache.filterAndApplyChunkInternal(halChunk,
+ TEST_MAX_NUM_MODIFIED_PER_CHUNK, TEST_MAX_NUM_REMOVED_PER_CHUNK);
+
+ expect.withMessage("Program list chunk applied with invalid program and identifiers")
+ .that(programListChunks).isEmpty();
+ }
+
private void verifyChunkListPurge(List<ProgramList.Chunk> chunks, boolean purge) {
if (chunks.isEmpty()) {
return;
diff --git a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/RadioModuleTest.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/RadioModuleTest.java
index 10ac05d..a952bde 100644
--- a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/RadioModuleTest.java
+++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/RadioModuleTest.java
@@ -16,13 +16,12 @@
package com.android.server.broadcastradio.aidl;
-import static com.google.common.truth.Truth.assertWithMessage;
-
import static org.junit.Assert.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -32,9 +31,13 @@
import android.hardware.radio.IAnnouncementListener;
import android.hardware.radio.ICloseHandle;
import android.hardware.radio.RadioManager;
+import android.os.ParcelableException;
import android.os.RemoteException;
+import com.google.common.truth.Expect;
+
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -50,6 +53,9 @@
private static final RadioManager.ModuleProperties TEST_MODULE_PROPERTIES =
AidlTestUtils.makeDefaultModuleProperties();
+ @Rule
+ public final Expect mExpect = Expect.create();
+
// Mocks
@Mock
private IBroadcastRadio mBroadcastRadioMock;
@@ -77,13 +83,13 @@
@Test
public void getService() {
- assertWithMessage("Service of radio module")
+ mExpect.withMessage("Service of radio module")
.that(mRadioModule.getService()).isEqualTo(mBroadcastRadioMock);
}
@Test
public void getProperties() {
- assertWithMessage("Module properties of radio module")
+ mExpect.withMessage("Module properties of radio module")
.that(mRadioModule.getProperties()).isEqualTo(TEST_MODULE_PROPERTIES);
}
@@ -93,7 +99,7 @@
Bitmap imageTest = mRadioModule.getImage(imageId);
- assertWithMessage("Image from radio module").that(imageTest).isNull();
+ mExpect.withMessage("Image from radio module").that(imageTest).isNull();
}
@Test
@@ -104,7 +110,7 @@
mRadioModule.getImage(invalidImageId);
});
- assertWithMessage("Exception for getting image with invalid ID")
+ mExpect.withMessage("Exception for getting image with invalid ID")
.that(thrown).hasMessageThat().contains("Image ID is missing");
}
@@ -117,6 +123,18 @@
}
@Test
+ public void addAnnouncementListener_whenHalThrowsRemoteException() throws Exception {
+ doThrow(new RuntimeException("HAL service died")).when(mBroadcastRadioMock)
+ .registerAnnouncementListener(any(), any());
+
+ ParcelableException thrown = assertThrows(ParcelableException.class, () ->
+ mRadioModule.addAnnouncementListener(mListenerMock, new int[]{TEST_ENABLED_TYPE}));
+
+ mExpect.withMessage("Exception for adding announcement listener when HAL service died")
+ .that(thrown).hasMessageThat().contains("unknown error");
+ }
+
+ @Test
public void onListUpdate_forAnnouncementListener() throws Exception {
android.hardware.broadcastradio.Announcement halAnnouncement =
AidlTestUtils.makeAnnouncement(TEST_ENABLED_TYPE, /* selectorFreq= */ 96300);
diff --git a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/TunerSessionTest.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/TunerSessionTest.java
index 755bcdb..4ded91d 100644
--- a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/TunerSessionTest.java
+++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/TunerSessionTest.java
@@ -421,6 +421,19 @@
}
@Test
+ public void tune_withClosedTuner_fails() throws Exception {
+ openAidlClients(/* numClients= */ 1);
+ ProgramSelector sel = AidlTestUtils.makeFmSelector(AM_FM_FREQUENCY_LIST[1]);
+ mTunerSessions[0].close();
+
+ IllegalStateException thrown = assertThrows(IllegalStateException.class,
+ () -> mTunerSessions[0].tune(sel));
+
+ expect.withMessage("Exception for tuning on closed tuner").that(thrown).hasMessageThat()
+ .contains("Tuner is closed");
+ }
+
+ @Test
public void step_withDirectionUp() throws Exception {
long initFreq = AM_FM_FREQUENCY_LIST[1];
ProgramSelector initialSel = AidlTestUtils.makeFmSelector(initFreq);
@@ -1149,6 +1162,20 @@
}
@Test
+ public void onCurrentProgramInfoChanged_withLowerSdkVersion_doesNotInvokesCallback()
+ throws Exception {
+ doReturn(false).when(() -> CompatChanges.isChangeEnabled(
+ eq(ConversionUtils.RADIO_U_VERSION_REQUIRED), anyInt()));
+ openAidlClients(/* numClients= */ 1);
+
+ mHalTunerCallback.onCurrentProgramInfoChanged(
+ AidlTestUtils.programInfoToHalProgramInfo(TEST_DAB_INFO));
+
+ verify(mAidlTunerCallbackMocks[0], after(CALLBACK_TIMEOUT_MS).never())
+ .onCurrentProgramInfoChanged(any());
+ }
+
+ @Test
public void onTuneFailed_forTunerCallback() throws Exception {
int numSessions = 3;
openAidlClients(numSessions);
@@ -1165,6 +1192,20 @@
}
@Test
+ public void onTuneFailed_withLowerSdkVersion_doesNotInvokesCallback()
+ throws Exception {
+ doReturn(false).when(() -> CompatChanges.isChangeEnabled(
+ eq(ConversionUtils.RADIO_U_VERSION_REQUIRED), anyInt()));
+ openAidlClients(/* numClients= */ 1);
+
+ mHalTunerCallback.onTuneFailed(Result.CANCELED,
+ ConversionUtils.programSelectorToHalProgramSelector(TEST_DAB_SELECTOR));
+
+ verify(mAidlTunerCallbackMocks[0], after(CALLBACK_TIMEOUT_MS).never())
+ .onTuneFailed(anyInt(), any());
+ }
+
+ @Test
public void onAntennaStateChange_forTunerCallback() throws Exception {
int numSessions = 3;
openAidlClients(numSessions);
@@ -1231,6 +1272,36 @@
}
}
+ @Test
+ public void openSession_withNonNullAntennaState() throws Exception {
+ boolean antennaConnected = false;
+ android.hardware.radio.ITunerCallback callback =
+ mock(android.hardware.radio.ITunerCallback.class);
+ openAidlClients(/* numClients= */ 1);
+ mHalTunerCallback.onAntennaStateChange(antennaConnected);
+ verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT).onAntennaState(antennaConnected);
+
+ mRadioModule.openSession(callback);
+
+ verify(callback, CALLBACK_TIMEOUT).onAntennaState(antennaConnected);
+ }
+
+ @Test
+ public void openSession_withNonNullCurrentProgramInfo() throws Exception {
+ openAidlClients(/* numClients= */ 1);
+ ProgramSelector initialSel = AidlTestUtils.makeFmSelector(AM_FM_FREQUENCY_LIST[1]);
+ RadioManager.ProgramInfo tuneInfo = AidlTestUtils.makeProgramInfo(initialSel,
+ SIGNAL_QUALITY);
+ mTunerSessions[0].tune(initialSel);
+ verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT).onCurrentProgramInfoChanged(tuneInfo);
+ android.hardware.radio.ITunerCallback callback =
+ mock(android.hardware.radio.ITunerCallback.class);
+
+ mRadioModule.openSession(callback);
+
+ verify(callback, CALLBACK_TIMEOUT).onCurrentProgramInfoChanged(tuneInfo);
+ }
+
private void openAidlClients(int numClients) throws Exception {
mAidlTunerCallbackMocks = new android.hardware.radio.ITunerCallback[numClients];
mTunerSessions = new TunerSession[numClients];
diff --git a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/AnnouncementAggregatorHidlTest.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/AnnouncementAggregatorHidlTest.java
index 5e99b28..8e0abff 100644
--- a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/AnnouncementAggregatorHidlTest.java
+++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/AnnouncementAggregatorHidlTest.java
@@ -16,11 +16,11 @@
package com.android.server.broadcastradio.hal2;
-import static com.google.common.truth.Truth.assertWithMessage;
-
import static org.junit.Assert.assertThrows;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
@@ -33,7 +33,10 @@
import android.os.IBinder;
import android.os.RemoteException;
+import com.google.common.truth.Expect;
+
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
@@ -55,6 +58,9 @@
private AnnouncementAggregator mAnnouncementAggregator;
private IBinder.DeathRecipient mDeathRecipient;
+ @Rule
+ public final Expect mExpect = Expect.create();
+
@Mock
private IAnnouncementListener mListenerMock;
@Mock
@@ -76,6 +82,19 @@
}
@Test
+ public void constructor_withBinderDied() throws Exception {
+ RemoteException remoteException = new RemoteException("Binder is died");
+ doThrow(remoteException).when(mBinderMock).linkToDeath(any(), anyInt());
+
+ RuntimeException thrown = assertThrows(RuntimeException.class,
+ () -> new com.android.server.broadcastradio.aidl.AnnouncementAggregator(
+ mListenerMock, mLock));
+
+ mExpect.withMessage("Exception for dead binder").that(thrown).hasMessageThat()
+ .contains(remoteException.getMessage());
+ }
+
+ @Test
public void onListUpdated_withOneModuleWatcher() throws Exception {
ArgumentCaptor<IAnnouncementListener> moduleWatcherCaptor =
ArgumentCaptor.forClass(IAnnouncementListener.class);
@@ -104,7 +123,7 @@
moduleWatcherCaptor.getValue().onListUpdated(Arrays.asList(mAnnouncementMocks[index]));
verify(mListenerMock, times(index + 1)).onListUpdated(announcementsCaptor.capture());
- assertWithMessage("Number of announcements %s after %s announcements were updated",
+ mExpect.withMessage("Number of announcements %s after %s announcements were updated",
announcementsCaptor.getValue(), index + 1)
.that(announcementsCaptor.getValue().size()).isEqualTo(index + 1);
}
@@ -132,7 +151,7 @@
() -> mAnnouncementAggregator.watchModule(mRadioModuleMocks[0],
TEST_ENABLED_TYPES));
- assertWithMessage("Exception for watching module after aggregator has been closed")
+ mExpect.withMessage("Exception for watching module after aggregator has been closed")
.that(thrown).hasMessageThat()
.contains("announcement aggregator has already been closed");
}
diff --git a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/ConvertTest.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/ConvertTest.java
index 3de4f5d..4cb012c 100644
--- a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/ConvertTest.java
+++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/ConvertTest.java
@@ -21,7 +21,6 @@
import android.hardware.broadcastradio.V2_0.DabTableEntry;
import android.hardware.broadcastradio.V2_0.IdentifierType;
import android.hardware.broadcastradio.V2_0.Properties;
-import android.hardware.broadcastradio.V2_0.VendorKeyValue;
import android.hardware.radio.Announcement;
import android.hardware.radio.ProgramSelector;
import android.hardware.radio.RadioManager;
@@ -149,6 +148,26 @@
}
@Test
+ public void propertiesFromHalProperties_withInvalidBand() {
+ AmFmRegionConfig amFmRegionConfig = new AmFmRegionConfig();
+ amFmRegionConfig.ranges = new ArrayList<>(Arrays.asList(createAmFmBandRange(
+ /* lowerBound= */ 50000, /* upperBound= */ 60000, /* spacing= */ 10),
+ createAmFmBandRange(FM_LOWER_LIMIT, FM_UPPER_LIMIT, FM_SPACING)));
+
+ RadioManager.ModuleProperties properties = convertToModuleProperties(amFmRegionConfig,
+ new ArrayList<>());
+
+ RadioManager.BandDescriptor[] bands = properties.getBands();
+ expect.withMessage("Band descriptors").that(bands).hasLength(1);
+ expect.withMessage("FM band frequency lower limit")
+ .that(bands[0].getLowerLimit()).isEqualTo(FM_LOWER_LIMIT);
+ expect.withMessage("FM band frequency upper limit")
+ .that(bands[0].getUpperLimit()).isEqualTo(FM_UPPER_LIMIT);
+ expect.withMessage("FM band frequency spacing")
+ .that(bands[0].getSpacing()).isEqualTo(FM_SPACING);
+ }
+
+ @Test
public void announcementFromHalAnnouncement_typesMatch() {
expect.withMessage("Announcement type")
.that(ANNOUNCEMENT.getType()).isEqualTo(TEST_ENABLED_TYPE);
@@ -173,20 +192,31 @@
.that(ANNOUNCEMENT.getVendorInfo()).isEmpty();
}
+ @Test
+ public void getBands_withInvalidFrequency() {
+ expect.withMessage("Band for invalid frequency")
+ .that(Utils.getBand(/* freq= */ 110000)).isEqualTo(FrequencyBand.UNKNOWN);
+ }
+
private static RadioManager.ModuleProperties convertToModuleProperties() {
AmFmRegionConfig amFmConfig = createAmFmRegionConfig();
List<DabTableEntry> dabTableEntries = Arrays.asList(
createDabTableEntry(DAB_ENTRY_LABEL_1, DAB_ENTRY_FREQUENCY_1),
createDabTableEntry(DAB_ENTRY_LABEL_2, DAB_ENTRY_FREQUENCY_2));
- Properties properties = createHalProperties();
+ return convertToModuleProperties(amFmConfig, dabTableEntries);
+ }
+
+ private static RadioManager.ModuleProperties convertToModuleProperties(
+ AmFmRegionConfig amFmConfig, List<DabTableEntry> dabTableEntries) {
+ Properties properties = createHalProperties();
return Convert.propertiesFromHal(TEST_ID, TEST_SERVICE_NAME, properties,
amFmConfig, dabTableEntries);
}
private static AmFmRegionConfig createAmFmRegionConfig() {
AmFmRegionConfig amFmRegionConfig = new AmFmRegionConfig();
- amFmRegionConfig.ranges = new ArrayList<AmFmBandRange>(Arrays.asList(
+ amFmRegionConfig.ranges = new ArrayList<>(Arrays.asList(
createAmFmBandRange(FM_LOWER_LIMIT, FM_UPPER_LIMIT, FM_SPACING),
createAmFmBandRange(AM_LOWER_LIMIT, AM_UPPER_LIMIT, AM_SPACING)));
return amFmRegionConfig;
@@ -216,7 +246,7 @@
halProperties.product = TEST_PRODUCT;
halProperties.version = TEST_VERSION;
halProperties.serial = TEST_SERIAL;
- halProperties.vendorInfo = new ArrayList<VendorKeyValue>(Arrays.asList(
+ halProperties.vendorInfo = new ArrayList<>(Arrays.asList(
TestUtils.makeVendorKeyValue(VENDOR_INFO_KEY_1, VENDOR_INFO_VALUE_1),
TestUtils.makeVendorKeyValue(VENDOR_INFO_KEY_2, VENDOR_INFO_VALUE_2)));
return halProperties;
diff --git a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/ProgramInfoCacheTest.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/ProgramInfoCacheTest.java
index 36a6430..015e9c0 100644
--- a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/ProgramInfoCacheTest.java
+++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/ProgramInfoCacheTest.java
@@ -17,6 +17,7 @@
import static org.junit.Assert.*;
+import android.hardware.broadcastradio.V2_0.ProgramIdentifier;
import android.hardware.broadcastradio.V2_0.ProgramListChunk;
import android.hardware.radio.ProgramList;
import android.hardware.radio.ProgramSelector;
@@ -34,6 +35,7 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -261,6 +263,25 @@
verifyChunkListRemoved(chunks, 1, TEST_DAB_UNIQUE_ID, TEST_VENDOR_UNIQUE_ID);
}
+ @Test
+ public void filterAndApplyChunkInternal_withInvalidIdentifier() {
+ ProgramInfoCache cache = new ProgramInfoCache(/* filter= */ null, /* complete= */ false,
+ TEST_AM_FM_INFO, TEST_RDS_INFO, TEST_DAB_INFO, TEST_VENDOR_INFO);
+ ArrayList<ProgramIdentifier> halRemoved = new ArrayList<>();
+ halRemoved.add(new ProgramIdentifier());
+ ProgramListChunk halChunk = new ProgramListChunk();
+ halChunk.complete = true;
+ halChunk.purge = false;
+ halChunk.modified = new ArrayList<>();
+ halChunk.removed = halRemoved;
+
+ List<ProgramList.Chunk> programListChunks = cache.filterAndApplyChunkInternal(halChunk,
+ /* maxNumModifiedPerChunk= */ 1, /* maxNumRemovedPerChunk= */ 1);
+
+ expect.withMessage("Program list chunk applied with invalid identifier")
+ .that(programListChunks).isEmpty();
+ }
+
// Verifies that:
// - The first chunk's purge flag matches expectPurge.
// - The last chunk's complete flag matches expectComplete.
diff --git a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/TunerSessionHidlTest.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/TunerSessionHidlTest.java
index 6edfa02..898ef57 100644
--- a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/TunerSessionHidlTest.java
+++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/TunerSessionHidlTest.java
@@ -29,8 +29,6 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.timeout;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
-import static com.google.common.truth.Truth.assertWithMessage;
-
import static org.junit.Assert.assertThrows;
import android.graphics.Bitmap;
@@ -57,8 +55,11 @@
import com.android.server.broadcastradio.ExtendedRadioMockitoTestCase;
import com.android.server.broadcastradio.RadioServiceUserController;
+import com.google.common.truth.Expect;
+
import org.junit.After;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -98,6 +99,9 @@
private ProgramInfo mHalCurrentInfo;
private TunerSession[] mTunerSessions;
+ @Rule
+ public final Expect mExpect = Expect.create();
+
@Mock
private UserHandle mUserHandleMock;
@Mock
@@ -206,7 +210,7 @@
openAidlClients(numSessions);
for (int index = 0; index < numSessions; index++) {
- assertWithMessage("Session of index %s close state", index)
+ mExpect.withMessage("Session of index %s close state", index)
.that(mTunerSessions[index].isClosed()).isFalse();
}
}
@@ -238,7 +242,7 @@
RadioManager.BandConfig config = mTunerSessions[0].getConfiguration();
- assertWithMessage("Session configuration").that(config)
+ mExpect.withMessage("Session configuration").that(config)
.isEqualTo(FM_BAND_CONFIG);
}
@@ -248,7 +252,7 @@
mTunerSessions[0].setMuted(/* mute= */ false);
- assertWithMessage("Session mute state after setting unmuted")
+ mExpect.withMessage("Session mute state after setting unmuted")
.that(mTunerSessions[0].isMuted()).isFalse();
}
@@ -258,7 +262,7 @@
mTunerSessions[0].setMuted(/* mute= */ true);
- assertWithMessage("Session mute state after setting muted")
+ mExpect.withMessage("Session mute state after setting muted")
.that(mTunerSessions[0].isMuted()).isTrue();
}
@@ -268,7 +272,7 @@
mTunerSessions[0].close();
- assertWithMessage("Close state of broadcast radio service session")
+ mExpect.withMessage("Close state of broadcast radio service session")
.that(mTunerSessions[0].isClosed()).isTrue();
}
@@ -282,11 +286,11 @@
for (int index = 0; index < numSessions; index++) {
if (index == closeIdx) {
- assertWithMessage(
+ mExpect.withMessage(
"Close state of broadcast radio service session of index %s", index)
.that(mTunerSessions[index].isClosed()).isTrue();
} else {
- assertWithMessage(
+ mExpect.withMessage(
"Close state of broadcast radio service session of index %s", index)
.that(mTunerSessions[index].isClosed()).isFalse();
}
@@ -301,7 +305,21 @@
mTunerSessions[0].close(errorCode);
verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT).onError(errorCode);
- assertWithMessage("Close state of broadcast radio service session")
+ mExpect.withMessage("Close state of broadcast radio service session")
+ .that(mTunerSessions[0].isClosed()).isTrue();
+ }
+
+ @Test
+ public void close_forMultipleTimes() throws Exception {
+ openAidlClients(/* numClients= */ 1);
+ int errorCode = RadioTuner.ERROR_SERVER_DIED;
+ mTunerSessions[0].close(errorCode);
+ verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT).onError(errorCode);
+
+ mTunerSessions[0].close(errorCode);
+
+ verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT).onError(errorCode);
+ mExpect.withMessage("State of closing broadcast radio service session twice")
.that(mTunerSessions[0].isClosed()).isTrue();
}
@@ -315,7 +333,7 @@
for (int index = 0; index < numSessions; index++) {
verify(mAidlTunerCallbackMocks[index], CALLBACK_TIMEOUT).onError(errorCode);
- assertWithMessage("Close state of broadcast radio service session of index %s", index)
+ mExpect.withMessage("Close state of broadcast radio service session of index %s", index)
.that(mTunerSessions[index].isClosed()).isTrue();
}
}
@@ -365,7 +383,7 @@
UnsupportedOperationException thrown = assertThrows(UnsupportedOperationException.class,
() -> mTunerSessions[0].tune(unsupportedSelector));
- assertWithMessage("Exception for tuning on unsupported program selector")
+ mExpect.withMessage("Exception for tuning on unsupported program selector")
.that(thrown).hasMessageThat().contains("tune: NOT_SUPPORTED");
}
@@ -393,11 +411,24 @@
mTunerSessions[0].tune(sel);
});
- assertWithMessage("Unknown error HAL exception when tuning")
+ mExpect.withMessage("Unknown error HAL exception when tuning")
.that(thrown).hasMessageThat().contains(Result.toString(Result.UNKNOWN_ERROR));
}
@Test
+ public void tune_withClosedTuner_fails() throws Exception {
+ openAidlClients(/* numClients= */ 1);
+ ProgramSelector sel = TestUtils.makeFmSelector(AM_FM_FREQUENCY_LIST[1]);
+ mTunerSessions[0].close();
+
+ IllegalStateException thrown = assertThrows(IllegalStateException.class,
+ () -> mTunerSessions[0].tune(sel));
+
+ mExpect.withMessage("Exception for tuning on closed tuner").that(thrown).hasMessageThat()
+ .contains("Tuner is closed");
+ }
+
+ @Test
public void step_withDirectionUp() throws Exception {
long initFreq = AM_FM_FREQUENCY_LIST[1];
ProgramSelector initialSel = TestUtils.makeFmSelector(initFreq);
@@ -454,7 +485,7 @@
mTunerSessions[0].step(/* directionDown= */ true, /* skipSubChannel= */ false);
});
- assertWithMessage("Exception for stepping when HAL is in invalid state")
+ mExpect.withMessage("Exception for stepping when HAL is in invalid state")
.that(thrown).hasMessageThat().contains(Result.toString(Result.INVALID_STATE));
}
@@ -533,7 +564,7 @@
mTunerSessions[0].seek(/* directionDown= */ true, /* skipSubChannel= */ false);
});
- assertWithMessage("Internal error HAL exception when seeking")
+ mExpect.withMessage("Internal error HAL exception when seeking")
.that(thrown).hasMessageThat().contains(Result.toString(Result.INTERNAL_ERROR));
}
@@ -566,7 +597,7 @@
mTunerSessions[0].cancel();
});
- assertWithMessage("Exception for canceling when HAL throws remote exception")
+ mExpect.withMessage("Exception for canceling when HAL throws remote exception")
.that(thrown).hasMessageThat().contains(exceptionMessage);
}
@@ -579,7 +610,7 @@
mTunerSessions[0].getImage(imageId);
});
- assertWithMessage("Get image exception")
+ mExpect.withMessage("Get image exception")
.that(thrown).hasMessageThat().contains("Image ID is missing");
}
@@ -590,7 +621,7 @@
Bitmap imageTest = mTunerSessions[0].getImage(imageId);
- assertWithMessage("Null image").that(imageTest).isEqualTo(null);
+ mExpect.withMessage("Null image").that(imageTest).isEqualTo(null);
}
@Test
@@ -603,7 +634,7 @@
mTunerSessions[0].getImage(/* id= */ 1);
});
- assertWithMessage("Exception for getting image when HAL throws remote exception")
+ mExpect.withMessage("Exception for getting image when HAL throws remote exception")
.that(thrown).hasMessageThat().contains(exceptionMessage);
}
@@ -649,7 +680,7 @@
mTunerSessions[0].startProgramListUpdates(/* filter= */ null);
});
- assertWithMessage("Unknown error HAL exception when updating program list")
+ mExpect.withMessage("Unknown error HAL exception when updating program list")
.that(thrown).hasMessageThat().contains(Result.toString(Result.UNKNOWN_ERROR));
}
@@ -686,7 +717,7 @@
boolean isSupported = mTunerSessions[0].isConfigFlagSupported(flag);
verify(mHalTunerSessionMock).isConfigFlagSet(eq(flag), any());
- assertWithMessage("Config flag %s is supported", flag).that(isSupported).isFalse();
+ mExpect.withMessage("Config flag %s is supported", flag).that(isSupported).isFalse();
}
@Test
@@ -697,7 +728,7 @@
boolean isSupported = mTunerSessions[0].isConfigFlagSupported(flag);
verify(mHalTunerSessionMock).isConfigFlagSet(eq(flag), any());
- assertWithMessage("Config flag %s is supported", flag).that(isSupported).isTrue();
+ mExpect.withMessage("Config flag %s is supported", flag).that(isSupported).isTrue();
}
@Test
@@ -709,7 +740,7 @@
mTunerSessions[0].setConfigFlag(flag, /* value= */ true);
});
- assertWithMessage("Exception for setting unsupported flag %s", flag)
+ mExpect.withMessage("Exception for setting unsupported flag %s", flag)
.that(thrown).hasMessageThat().contains("setConfigFlag: NOT_SUPPORTED");
}
@@ -755,7 +786,7 @@
mTunerSessions[0].isConfigFlagSet(flag);
});
- assertWithMessage("Exception for checking if unsupported flag %s is set", flag)
+ mExpect.withMessage("Exception for checking if unsupported flag %s is set", flag)
.that(thrown).hasMessageThat().contains("isConfigFlagSet: NOT_SUPPORTED");
}
@@ -768,7 +799,7 @@
boolean isSet = mTunerSessions[0].isConfigFlagSet(flag);
- assertWithMessage("Config flag %s is set", flag)
+ mExpect.withMessage("Config flag %s is set", flag)
.that(isSet).isEqualTo(expectedConfigFlagValue);
}
@@ -782,7 +813,7 @@
mTunerSessions[0].isConfigFlagSet(flag);
});
- assertWithMessage("Exception for checking config flag when HAL throws remote exception")
+ mExpect.withMessage("Exception for checking config flag when HAL throws remote exception")
.that(thrown).hasMessageThat().contains("Failed to check flag");
}
@@ -822,7 +853,7 @@
mTunerSessions[0].setParameters(parametersSet);
});
- assertWithMessage("Exception for setting parameters when HAL throws remote exception")
+ mExpect.withMessage("Exception for setting parameters when HAL throws remote exception")
.that(thrown).hasMessageThat().contains(exceptionMessage);
}
@@ -848,7 +879,7 @@
mTunerSessions[0].getParameters(parameterKeys);
});
- assertWithMessage("Exception for getting parameters when HAL throws remote exception")
+ mExpect.withMessage("Exception for getting parameters when HAL throws remote exception")
.that(thrown).hasMessageThat().contains(exceptionMessage);
}
@@ -894,6 +925,36 @@
}
}
+ @Test
+ public void openSession_withNonNullAntennaState() throws Exception {
+ boolean antennaConnected = false;
+ android.hardware.radio.ITunerCallback callback =
+ mock(android.hardware.radio.ITunerCallback.class);
+ openAidlClients(/* numClients= */ 1);
+ mHalTunerCallback.onAntennaStateChange(antennaConnected);
+ verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT).onAntennaState(antennaConnected);
+
+ mRadioModule.openSession(callback);
+
+ verify(callback, CALLBACK_TIMEOUT).onAntennaState(antennaConnected);
+ }
+
+ @Test
+ public void openSession_withNonNullCurrentProgramInfo() throws Exception {
+ openAidlClients(/* numClients= */ 1);
+ ProgramSelector initialSel = TestUtils.makeFmSelector(AM_FM_FREQUENCY_LIST[1]);
+ RadioManager.ProgramInfo tuneInfo = TestUtils.makeProgramInfo(initialSel,
+ SIGNAL_QUALITY);
+ mTunerSessions[0].tune(initialSel);
+ verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT).onCurrentProgramInfoChanged(tuneInfo);
+ android.hardware.radio.ITunerCallback callback =
+ mock(android.hardware.radio.ITunerCallback.class);
+
+ mRadioModule.openSession(callback);
+
+ verify(callback, CALLBACK_TIMEOUT).onCurrentProgramInfoChanged(tuneInfo);
+ }
+
private void openAidlClients(int numClients) throws Exception {
mAidlTunerCallbackMocks = new android.hardware.radio.ITunerCallback[numClients];
mTunerSessions = new TunerSession[numClients];
diff --git a/core/tests/coretests/src/android/view/ViewFrameRateTest.java b/core/tests/coretests/src/android/view/ViewFrameRateTest.java
index 35b984a..169300a 100644
--- a/core/tests/coretests/src/android/view/ViewFrameRateTest.java
+++ b/core/tests/coretests/src/android/view/ViewFrameRateTest.java
@@ -45,6 +45,7 @@
import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
+import android.sysprop.ViewProperties;
import android.util.DisplayMetrics;
import android.widget.FrameLayout;
import android.widget.ProgressBar;
@@ -101,6 +102,9 @@
@RequiresFlagsEnabled({FLAG_VIEW_VELOCITY_API,
FLAG_TOOLKIT_FRAME_RATE_VIEW_ENABLING_READ_ONLY})
public void frameRateChangesWhenContentMoves() throws Throwable {
+ if (!ViewProperties.vrr_enabled().orElse(true)) {
+ return;
+ }
waitForFrameRateCategoryToSettle();
mActivityRule.runOnUiThread(() -> {
mMovingView.offsetLeftAndRight(100);
@@ -127,6 +131,9 @@
@Test
@RequiresFlagsEnabled(FLAG_VIEW_VELOCITY_API)
public void frameBoostDisable() throws Throwable {
+ if (!ViewProperties.vrr_enabled().orElse(true)) {
+ return;
+ }
mActivityRule.runOnUiThread(() -> {
long now = SystemClock.uptimeMillis();
MotionEvent down = MotionEvent.obtain(
@@ -155,6 +162,9 @@
FLAG_TOOLKIT_FRAME_RATE_VELOCITY_MAPPING_READ_ONLY,
FLAG_TOOLKIT_FRAME_RATE_VIEW_ENABLING_READ_ONLY})
public void lowVelocity60() throws Throwable {
+ if (!ViewProperties.vrr_enabled().orElse(true)) {
+ return;
+ }
mActivityRule.runOnUiThread(() -> {
ViewGroup.LayoutParams layoutParams = mMovingView.getLayoutParams();
layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT;
@@ -175,6 +185,9 @@
FLAG_TOOLKIT_FRAME_RATE_VELOCITY_MAPPING_READ_ONLY,
FLAG_TOOLKIT_FRAME_RATE_VIEW_ENABLING_READ_ONLY})
public void velocityWithChildMovement() throws Throwable {
+ if (!ViewProperties.vrr_enabled().orElse(true)) {
+ return;
+ }
FrameLayout frameLayout = new FrameLayout(mActivity);
mActivityRule.runOnUiThread(() -> {
ViewGroup.LayoutParams fullSize = new ViewGroup.LayoutParams(
@@ -201,6 +214,9 @@
FLAG_TOOLKIT_FRAME_RATE_VELOCITY_MAPPING_READ_ONLY,
FLAG_TOOLKIT_FRAME_RATE_VIEW_ENABLING_READ_ONLY})
public void highVelocity120() throws Throwable {
+ if (!ViewProperties.vrr_enabled().orElse(true)) {
+ return;
+ }
mActivityRule.runOnUiThread(() -> {
ViewGroup.LayoutParams layoutParams = mMovingView.getLayoutParams();
layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT;
@@ -222,6 +238,9 @@
@RequiresFlagsEnabled({FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY,
FLAG_TOOLKIT_FRAME_RATE_VIEW_ENABLING_READ_ONLY})
public void noVelocityUsesCategorySmall() throws Throwable {
+ if (!ViewProperties.vrr_enabled().orElse(true)) {
+ return;
+ }
final CountDownLatch drawLatch1 = new CountDownLatch(1);
mActivityRule.runOnUiThread(() -> {
DisplayMetrics displayMetrics = mActivity.getResources().getDisplayMetrics();
@@ -259,6 +278,9 @@
@RequiresFlagsEnabled({FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY,
FLAG_TOOLKIT_FRAME_RATE_VIEW_ENABLING_READ_ONLY})
public void noVelocityUsesCategoryNarrowWidth() throws Throwable {
+ if (!ViewProperties.vrr_enabled().orElse(true)) {
+ return;
+ }
final CountDownLatch drawLatch1 = new CountDownLatch(1);
mActivityRule.runOnUiThread(() -> {
DisplayMetrics displayMetrics = mActivity.getResources().getDisplayMetrics();
@@ -295,6 +317,9 @@
@RequiresFlagsEnabled({FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY,
FLAG_TOOLKIT_FRAME_RATE_VIEW_ENABLING_READ_ONLY})
public void noVelocityUsesCategoryNarrowHeight() throws Throwable {
+ if (!ViewProperties.vrr_enabled().orElse(true)) {
+ return;
+ }
final CountDownLatch drawLatch1 = new CountDownLatch(1);
mActivityRule.runOnUiThread(() -> {
DisplayMetrics displayMetrics = mActivity.getResources().getDisplayMetrics();
@@ -331,6 +356,9 @@
@RequiresFlagsEnabled({FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY,
FLAG_TOOLKIT_FRAME_RATE_VIEW_ENABLING_READ_ONLY})
public void noVelocityUsesCategoryLargeWidth() throws Throwable {
+ if (!ViewProperties.vrr_enabled().orElse(true)) {
+ return;
+ }
final CountDownLatch drawLatch1 = new CountDownLatch(1);
mActivityRule.runOnUiThread(() -> {
DisplayMetrics displayMetrics = mActivity.getResources().getDisplayMetrics();
@@ -367,6 +395,9 @@
@RequiresFlagsEnabled({FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY,
FLAG_TOOLKIT_FRAME_RATE_VIEW_ENABLING_READ_ONLY})
public void noVelocityUsesCategoryLargeHeight() throws Throwable {
+ if (!ViewProperties.vrr_enabled().orElse(true)) {
+ return;
+ }
final CountDownLatch drawLatch1 = new CountDownLatch(1);
mActivityRule.runOnUiThread(() -> {
DisplayMetrics displayMetrics = mActivity.getResources().getDisplayMetrics();
@@ -403,6 +434,9 @@
@RequiresFlagsEnabled({FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY,
FLAG_TOOLKIT_FRAME_RATE_VIEW_ENABLING_READ_ONLY})
public void defaultNormal() throws Throwable {
+ if (!ViewProperties.vrr_enabled().orElse(true)) {
+ return;
+ }
mActivityRule.runOnUiThread(() -> {
View parent = (View) mMovingView.getParent();
ViewGroup.LayoutParams layoutParams = mMovingView.getLayoutParams();
@@ -427,6 +461,9 @@
FLAG_TOOLKIT_FRAME_RATE_VELOCITY_MAPPING_READ_ONLY
})
public void frameRateAndCategory() throws Throwable {
+ if (!ViewProperties.vrr_enabled().orElse(true)) {
+ return;
+ }
mMovingView.setRequestedFrameRate(View.REQUESTED_FRAME_RATE_CATEGORY_NO_PREFERENCE);
waitForFrameRateCategoryToSettle();
mActivityRule.runOnUiThread(() -> {
@@ -447,6 +484,9 @@
FLAG_TOOLKIT_FRAME_RATE_VIEW_ENABLING_READ_ONLY
})
public void willNotDrawUsesCategory() throws Throwable {
+ if (!ViewProperties.vrr_enabled().orElse(true)) {
+ return;
+ }
mActivityRule.runOnUiThread(() -> {
mMovingView.setWillNotDraw(true);
mMovingView.setRequestedFrameRate(View.REQUESTED_FRAME_RATE_CATEGORY_LOW);
@@ -480,6 +520,9 @@
@RequiresFlagsEnabled({FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY,
FLAG_TOOLKIT_FRAME_RATE_VIEW_ENABLING_READ_ONLY})
public void intermittentDoubleInvalidate() throws Throwable {
+ if (!ViewProperties.vrr_enabled().orElse(true)) {
+ return;
+ }
View parent = (View) mMovingView.getParent();
mActivityRule.runOnUiThread(() -> {
parent.setWillNotDraw(false);
@@ -526,6 +569,9 @@
FLAG_TOOLKIT_FRAME_RATE_VIEW_ENABLING_READ_ONLY
})
public void sameFrameMotion() throws Throwable {
+ if (!ViewProperties.vrr_enabled().orElse(true)) {
+ return;
+ }
mMovingView.setRequestedFrameRate(View.REQUESTED_FRAME_RATE_CATEGORY_NO_PREFERENCE);
waitForFrameRateCategoryToSettle();
@@ -549,6 +595,9 @@
FLAG_TOOLKIT_FRAME_RATE_VIEW_ENABLING_READ_ONLY
})
public void frameRateReset() throws Throwable {
+ if (!ViewProperties.vrr_enabled().orElse(true)) {
+ return;
+ }
mMovingView.setRequestedFrameRate(120f);
waitForFrameRateCategoryToSettle();
mActivityRule.runOnUiThread(() -> mMovingView.setVisibility(View.INVISIBLE));
@@ -570,6 +619,9 @@
FLAG_TOOLKIT_FRAME_RATE_VIEW_ENABLING_READ_ONLY
})
public void frameRateResetWithInvalidations() throws Throwable {
+ if (!ViewProperties.vrr_enabled().orElse(true)) {
+ return;
+ }
mMovingView.setRequestedFrameRate(120f);
waitForFrameRateCategoryToSettle();
mMovingView.setRequestedFrameRate(View.REQUESTED_FRAME_RATE_CATEGORY_NORMAL);
@@ -590,6 +642,9 @@
FLAG_TOOLKIT_FRAME_RATE_VIEW_ENABLING_READ_ONLY
})
public void testQuickTouchBoost() throws Throwable {
+ if (!ViewProperties.vrr_enabled().orElse(true)) {
+ return;
+ }
mActivityRule.runOnUiThread(() -> {
mMovingView.setRequestedFrameRate(View.REQUESTED_FRAME_RATE_CATEGORY_LOW);
ViewGroup.LayoutParams layoutParams = mMovingView.getLayoutParams();
@@ -630,6 +685,9 @@
com.android.graphics.surfaceflinger.flags.Flags.FLAG_VRR_BUGFIX_24Q4
})
public void idleDetected() throws Throwable {
+ if (!ViewProperties.vrr_enabled().orElse(true)) {
+ return;
+ }
waitForFrameRateCategoryToSettle();
mActivityRule.runOnUiThread(() -> {
mMovingView.setRequestedFrameRate(View.REQUESTED_FRAME_RATE_CATEGORY_HIGH);
@@ -654,6 +712,9 @@
com.android.graphics.surfaceflinger.flags.Flags.FLAG_VRR_BUGFIX_24Q4
})
public void vectorDrawableFrameRate() throws Throwable {
+ if (!ViewProperties.vrr_enabled().orElse(true)) {
+ return;
+ }
final ProgressBar[] progressBars = new ProgressBar[3];
final ViewGroup[] parents = new ViewGroup[1];
mActivityRule.runOnUiThread(() -> {
@@ -711,6 +772,9 @@
com.android.graphics.surfaceflinger.flags.Flags.FLAG_VRR_BUGFIX_24Q4
})
public void renderNodeAnimatorFrameRateCanceled() throws Throwable {
+ if (!ViewProperties.vrr_enabled().orElse(true)) {
+ return;
+ }
mMovingView.setRequestedFrameRate(View.REQUESTED_FRAME_RATE_CATEGORY_NO_PREFERENCE);
waitForFrameRateCategoryToSettle();
@@ -748,6 +812,9 @@
com.android.graphics.surfaceflinger.flags.Flags.FLAG_VRR_BUGFIX_24Q4
})
public void renderNodeAnimatorFrameRateRemoved() throws Throwable {
+ if (!ViewProperties.vrr_enabled().orElse(true)) {
+ return;
+ }
mMovingView.setRequestedFrameRate(View.REQUESTED_FRAME_RATE_CATEGORY_NO_PREFERENCE);
waitForFrameRateCategoryToSettle();
diff --git a/core/tests/coretests/src/android/view/ViewRootImplTest.java b/core/tests/coretests/src/android/view/ViewRootImplTest.java
index 94e187a..06cb0ee 100644
--- a/core/tests/coretests/src/android/view/ViewRootImplTest.java
+++ b/core/tests/coretests/src/android/view/ViewRootImplTest.java
@@ -72,6 +72,7 @@
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.platform.test.flag.junit.SetFlagsRule;
import android.provider.Settings;
+import android.sysprop.ViewProperties;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.WindowInsets.Side;
@@ -503,6 +504,9 @@
@RequiresFlagsEnabled({FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY,
FLAG_TOOLKIT_FRAME_RATE_VIEW_ENABLING_READ_ONLY})
public void votePreferredFrameRate_getDefaultValues() {
+ if (!ViewProperties.vrr_enabled().orElse(true)) {
+ return;
+ }
ViewRootImpl viewRootImpl = new ViewRootImpl(sContext,
sContext.getDisplayNoVerify());
assertEquals(FRAME_RATE_CATEGORY_DEFAULT,
@@ -521,6 +525,9 @@
FLAG_TOOLKIT_FRAME_RATE_BY_SIZE_READ_ONLY,
FLAG_TOOLKIT_FRAME_RATE_VIEW_ENABLING_READ_ONLY})
public void votePreferredFrameRate_voteFrameRateCategory_visibility_bySize() throws Throwable {
+ if (!ViewProperties.vrr_enabled().orElse(true)) {
+ return;
+ }
mView = new View(sContext);
attachViewToWindow(mView);
mViewRootImpl = mView.getViewRootImpl();
@@ -558,6 +565,9 @@
FLAG_TOOLKIT_FRAME_RATE_BY_SIZE_READ_ONLY,
FLAG_TOOLKIT_FRAME_RATE_VIEW_ENABLING_READ_ONLY})
public void votePreferredFrameRate_voteFrameRateCategory_smallSize_bySize() throws Throwable {
+ if (!ViewProperties.vrr_enabled().orElse(true)) {
+ return;
+ }
mView = new View(sContext);
WindowManager.LayoutParams wmlp = new WindowManager.LayoutParams(TYPE_APPLICATION_OVERLAY);
wmlp.token = new Binder(); // Set a fake token to bypass 'is your activity running' check
@@ -590,6 +600,9 @@
FLAG_TOOLKIT_FRAME_RATE_BY_SIZE_READ_ONLY,
FLAG_TOOLKIT_FRAME_RATE_VIEW_ENABLING_READ_ONLY})
public void votePreferredFrameRate_voteFrameRateCategory_normalSize_bySize() throws Throwable {
+ if (!ViewProperties.vrr_enabled().orElse(true)) {
+ return;
+ }
mView = new View(sContext);
WindowManager.LayoutParams wmlp = new WindowManager.LayoutParams(TYPE_APPLICATION_OVERLAY);
wmlp.token = new Binder(); // Set a fake token to bypass 'is your activity running' check
@@ -627,6 +640,9 @@
FLAG_TOOLKIT_FRAME_RATE_VIEW_ENABLING_READ_ONLY})
public void votePreferredFrameRate_voteFrameRateCategory_visibility_defaultHigh()
throws Throwable {
+ if (!ViewProperties.vrr_enabled().orElse(true)) {
+ return;
+ }
mView = new View(sContext);
WindowManager.LayoutParams wmlp = new WindowManager.LayoutParams(TYPE_APPLICATION_OVERLAY);
wmlp.token = new Binder(); // Set a fake token to bypass 'is your activity running' check
@@ -688,6 +704,9 @@
FLAG_TOOLKIT_FRAME_RATE_VIEW_ENABLING_READ_ONLY})
public void votePreferredFrameRate_voteFrameRateCategory_smallSize_defaultHigh()
throws Throwable {
+ if (!ViewProperties.vrr_enabled().orElse(true)) {
+ return;
+ }
mView = new View(sContext);
WindowManager.LayoutParams wmlp = new WindowManager.LayoutParams(TYPE_APPLICATION_OVERLAY);
wmlp.token = new Binder(); // Set a fake token to bypass 'is your activity running' check
@@ -723,6 +742,9 @@
FLAG_TOOLKIT_FRAME_RATE_VIEW_ENABLING_READ_ONLY})
public void votePreferredFrameRate_voteFrameRateCategory_normalSize_defaultHigh()
throws Throwable {
+ if (!ViewProperties.vrr_enabled().orElse(true)) {
+ return;
+ }
mView = new View(sContext);
WindowManager.LayoutParams wmlp = new WindowManager.LayoutParams(TYPE_APPLICATION_OVERLAY);
wmlp.token = new Binder(); // Set a fake token to bypass 'is your activity running' check
@@ -758,6 +780,9 @@
@RequiresFlagsEnabled({FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY,
FLAG_TOOLKIT_FRAME_RATE_VIEW_ENABLING_READ_ONLY})
public void votePreferredFrameRate_voteFrameRateCategory_aggregate() {
+ if (!ViewProperties.vrr_enabled().orElse(true)) {
+ return;
+ }
mView = new View(sContext);
attachViewToWindow(mView);
mViewRootImpl = mView.getViewRootImpl();
@@ -804,6 +829,9 @@
@RequiresFlagsEnabled({FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY,
FLAG_TOOLKIT_FRAME_RATE_VIEW_ENABLING_READ_ONLY})
public void votePreferredFrameRate_voteFrameRate_aggregate() {
+ if (!ViewProperties.vrr_enabled().orElse(true)) {
+ return;
+ }
mView = new View(sContext);
attachViewToWindow(mView);
mViewRootImpl = mView.getViewRootImpl();
@@ -876,6 +904,9 @@
FLAG_TOOLKIT_FRAME_RATE_FUNCTION_ENABLING_READ_ONLY,
FLAG_TOOLKIT_FRAME_RATE_VIEW_ENABLING_READ_ONLY})
public void votePreferredFrameRate_voteFrameRate_category() throws Throwable {
+ if (!ViewProperties.vrr_enabled().orElse(true)) {
+ return;
+ }
mView = new View(sContext);
attachViewToWindow(mView);
sInstrumentation.waitForIdleSync();
@@ -930,6 +961,9 @@
FLAG_TOOLKIT_FRAME_RATE_FUNCTION_ENABLING_READ_ONLY,
FLAG_TOOLKIT_FRAME_RATE_VIEW_ENABLING_READ_ONLY})
public void votePreferredFrameRate_voteFrameRateCategory_velocityToHigh() throws Throwable {
+ if (!ViewProperties.vrr_enabled().orElse(true)) {
+ return;
+ }
mView = new View(sContext);
WindowManager.LayoutParams wmlp = new WindowManager.LayoutParams(TYPE_APPLICATION_OVERLAY);
wmlp.token = new Binder(); // Set a fake token to bypass 'is your activity running' check
@@ -973,6 +1007,9 @@
@RequiresFlagsEnabled({FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY,
FLAG_TOOLKIT_FRAME_RATE_VIEW_ENABLING_READ_ONLY})
public void votePreferredFrameRate_insetsAnimation() {
+ if (!ViewProperties.vrr_enabled().orElse(true)) {
+ return;
+ }
mView = new View(sContext);
WindowManager.LayoutParams wmlp = new WindowManager.LayoutParams(TYPE_APPLICATION_OVERLAY);
wmlp.token = new Binder(); // Set a fake token to bypass 'is your activity running' check
@@ -1010,6 +1047,9 @@
@RequiresFlagsEnabled({FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY,
FLAG_TOOLKIT_FRAME_RATE_VIEW_ENABLING_READ_ONLY})
public void votePreferredFrameRate_frameRateBoostOnTouch() {
+ if (!ViewProperties.vrr_enabled().orElse(true)) {
+ return;
+ }
mView = new View(sContext);
attachViewToWindow(mView);
sInstrumentation.waitForIdleSync();
@@ -1043,6 +1083,9 @@
@RequiresFlagsEnabled({FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY,
FLAG_TOOLKIT_FRAME_RATE_VIEW_ENABLING_READ_ONLY})
public void votePreferredFrameRate_voteFrameRateTimeOut() throws InterruptedException {
+ if (!ViewProperties.vrr_enabled().orElse(true)) {
+ return;
+ }
final long delay = 200L;
mView = new View(sContext);
@@ -1082,6 +1125,9 @@
FLAG_TOOLKIT_FRAME_RATE_FUNCTION_ENABLING_READ_ONLY,
FLAG_TOOLKIT_FRAME_RATE_VIEW_ENABLING_READ_ONLY})
public void votePreferredFrameRate_voteFrameRateOnly() throws Throwable {
+ if (!ViewProperties.vrr_enabled().orElse(true)) {
+ return;
+ }
mView = new View(sContext);
float frameRate = 20;
attachViewToWindow(mView);
@@ -1133,6 +1179,9 @@
FLAG_TOOLKIT_FRAME_RATE_FUNCTION_ENABLING_READ_ONLY,
FLAG_TOOLKIT_FRAME_RATE_VIEW_ENABLING_READ_ONLY})
public void votePreferredFrameRate_infrequentLayer_defaultHigh() throws Throwable {
+ if (!ViewProperties.vrr_enabled().orElse(true)) {
+ return;
+ }
final long delay = 200L;
mView = new View(sContext);
@@ -1175,11 +1224,8 @@
// Infrequent update
Thread.sleep(delay);
- // Even though this is not a small View, step 3 is triggered by this flag, which
- // brings intermittent to LOW
- int intermittentExpected = toolkitFrameRateBySizeReadOnly()
- ? FRAME_RATE_CATEGORY_LOW
- : FRAME_RATE_CATEGORY_NORMAL;
+ // The expected category is normal for intermittent.
+ int intermittentExpected = FRAME_RATE_CATEGORY_NORMAL;
sInstrumentation.runOnMainSync(() -> {
mView.invalidate();
@@ -1211,6 +1257,9 @@
@RequiresFlagsEnabled({FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY,
FLAG_TOOLKIT_FRAME_RATE_VIEW_ENABLING_READ_ONLY})
public void votePreferredFrameRate_isFrameRatePowerSavingsBalanced() {
+ if (!ViewProperties.vrr_enabled().orElse(true)) {
+ return;
+ }
mView = new View(sContext);
attachViewToWindow(mView);
sInstrumentation.waitForIdleSync();
@@ -1245,6 +1294,9 @@
FLAG_TOOLKIT_FRAME_RATE_FUNCTION_ENABLING_READ_ONLY,
FLAG_TOOLKIT_FRAME_RATE_VIEW_ENABLING_READ_ONLY})
public void votePreferredFrameRate_applyTextureViewHeuristic() throws Throwable {
+ if (!ViewProperties.vrr_enabled().orElse(true)) {
+ return;
+ }
final long delay = 30L;
mView = new TextureView(sContext);
@@ -1289,6 +1341,9 @@
@Test
@RequiresFlagsEnabled(FLAG_TOOLKIT_FRAME_RATE_VIEW_ENABLING_READ_ONLY)
public void votePreferredFrameRate_velocityVotedAfterOnDraw() throws Throwable {
+ if (!ViewProperties.vrr_enabled().orElse(true)) {
+ return;
+ }
mView = new View(sContext);
double delta = 0.1;
float pixelsPerSecond = 1000_000;
diff --git a/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java b/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java
index d4482f2..b0190a5 100644
--- a/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java
+++ b/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java
@@ -112,7 +112,7 @@
doReturn(mApplicationInfo).when(mContext).getApplicationInfo();
mDispatcher = new WindowOnBackInvokedDispatcher(mContext, Looper.getMainLooper());
- mDispatcher.attachToWindow(mWindowSession, mWindow, null, mImeBackAnimationController);
+ mDispatcher.attachToWindow(mWindowSession, mWindow, mImeBackAnimationController);
}
private void waitForIdle() {
@@ -455,26 +455,25 @@
@Test
public void registerImeCallbacks_onBackInvokedCallbackEnabled() throws RemoteException {
- verifyImeCallackRegistrations();
- }
-
- @Test
- public void registerImeCallbacks_onBackInvokedCallbackDisabled() throws RemoteException {
- doReturn(false).when(mApplicationInfo).isOnBackInvokedCallbackEnabled();
- verifyImeCallackRegistrations();
- }
-
- private void verifyImeCallackRegistrations() throws RemoteException {
- // verify default callback is replaced with ImeBackAnimationController
- mDispatcher.registerOnBackInvokedCallbackUnchecked(mDefaultImeCallback, PRIORITY_DEFAULT);
+ mDispatcher.registerOnBackInvokedCallback(PRIORITY_DEFAULT, mDefaultImeCallback);
assertCallbacksSize(/* default */ 1, /* overlay */ 0);
assertSetCallbackInfo();
assertTopCallback(mImeBackAnimationController);
- // verify regular ime callback is successfully registered
- mDispatcher.registerOnBackInvokedCallbackUnchecked(mImeCallback, PRIORITY_DEFAULT);
+ mDispatcher.registerOnBackInvokedCallback(PRIORITY_DEFAULT, mImeCallback);
assertCallbacksSize(/* default */ 2, /* overlay */ 0);
assertSetCallbackInfo();
assertTopCallback(mImeCallback);
}
+
+ @Test
+ public void registerImeCallbacks_legacyBack() throws RemoteException {
+ doReturn(false).when(mApplicationInfo).isOnBackInvokedCallbackEnabled();
+
+ mDispatcher.registerOnBackInvokedCallback(PRIORITY_DEFAULT, mDefaultImeCallback);
+ assertNoSetCallbackInfo();
+
+ mDispatcher.registerOnBackInvokedCallback(PRIORITY_DEFAULT, mImeCallback);
+ assertNoSetCallbackInfo();
+ }
}
diff --git a/core/tests/hdmitests/src/android/hardware/hdmi/HdmiDeviceInfoTest.java b/core/tests/hdmitests/src/android/hardware/hdmi/HdmiDeviceInfoTest.java
old mode 100755
new mode 100644
diff --git a/core/tests/hdmitests/src/android/hardware/hdmi/HdmiPortInfoTest.java b/core/tests/hdmitests/src/android/hardware/hdmi/HdmiPortInfoTest.java
old mode 100755
new mode 100644
diff --git a/data/sounds/alarms/material/ogg/Awaken_OG7_1ch_48k.ogg b/data/sounds/alarms/material/ogg/Awaken_OG7_1ch_48k.ogg
old mode 100755
new mode 100644
Binary files differ
diff --git a/data/sounds/alarms/material/ogg/Bounce_OG7_1ch_48k.ogg b/data/sounds/alarms/material/ogg/Bounce_OG7_1ch_48k.ogg
old mode 100755
new mode 100644
Binary files differ
diff --git a/data/sounds/alarms/material/ogg/Drip_OG7_1ch_48k.ogg b/data/sounds/alarms/material/ogg/Drip_OG7_1ch_48k.ogg
old mode 100755
new mode 100644
Binary files differ
diff --git a/data/sounds/alarms/material/ogg/Gallop_OG7_1ch_48k.ogg b/data/sounds/alarms/material/ogg/Gallop_OG7_1ch_48k.ogg
old mode 100755
new mode 100644
Binary files differ
diff --git a/data/sounds/alarms/material/ogg/Nudge_OG7_1ch_48k.ogg b/data/sounds/alarms/material/ogg/Nudge_OG7_1ch_48k.ogg
old mode 100755
new mode 100644
Binary files differ
diff --git a/data/sounds/alarms/material/ogg/Orbit_OG7_1ch_48k.ogg b/data/sounds/alarms/material/ogg/Orbit_OG7_1ch_48k.ogg
old mode 100755
new mode 100644
Binary files differ
diff --git a/data/sounds/alarms/material/ogg/Rise_OG7_1ch_48k.ogg b/data/sounds/alarms/material/ogg/Rise_OG7_1ch_48k.ogg
old mode 100755
new mode 100644
Binary files differ
diff --git a/data/sounds/alarms/material/ogg/Sway_OG7_1ch_48k.ogg b/data/sounds/alarms/material/ogg/Sway_OG7_1ch_48k.ogg
old mode 100755
new mode 100644
Binary files differ
diff --git a/data/sounds/alarms/material/ogg/Wag_OG7_1ch_48k.ogg b/data/sounds/alarms/material/ogg/Wag_OG7_1ch_48k.ogg
old mode 100755
new mode 100644
Binary files differ
diff --git a/docs/downloads/training/LocationUpdates.zip b/docs/downloads/training/LocationUpdates.zip
old mode 100755
new mode 100644
Binary files differ
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 0119289..0fd21f3 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
@@ -30,6 +30,7 @@
import android.content.Context;
import android.content.res.Configuration;
import android.database.ContentObserver;
+import android.graphics.Rect;
import android.hardware.input.InputManager;
import android.net.Uri;
import android.os.Bundle;
@@ -47,6 +48,7 @@
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.RemoteAnimationTarget;
+import android.view.WindowManager;
import android.window.BackAnimationAdapter;
import android.window.BackEvent;
import android.window.BackMotionEvent;
@@ -119,6 +121,9 @@
private final ShellCommandHandler mShellCommandHandler;
private final ShellExecutor mShellExecutor;
private final Handler mBgHandler;
+ private final WindowManager mWindowManager;
+ @VisibleForTesting
+ final Rect mTouchableArea = new Rect();
/**
* Tracks the current user back gesture.
@@ -222,6 +227,8 @@
mShellBackAnimationRegistry = shellBackAnimationRegistry;
mLatencyTracker = LatencyTracker.getInstance(mContext);
mShellCommandHandler = shellCommandHandler;
+ mWindowManager = context.getSystemService(WindowManager.class);
+ updateTouchableArea();
}
private void onInit() {
@@ -283,6 +290,11 @@
@Override
public void onConfigurationChanged(Configuration newConfig) {
mShellBackAnimationRegistry.onConfigurationChanged(newConfig);
+ updateTouchableArea();
+ }
+
+ private void updateTouchableArea() {
+ mTouchableArea.set(mWindowManager.getCurrentWindowMetrics().getBounds());
}
@Override
@@ -416,11 +428,18 @@
if (!shouldDispatchToAnimator && mActiveCallback != null) {
mCurrentTracker.updateStartLocation();
tryDispatchOnBackStarted(mActiveCallback, mCurrentTracker.createStartEvent(null));
+ if (mBackNavigationInfo != null && !isAppProgressGenerationAllowed()) {
+ tryPilferPointers();
+ }
} else if (shouldDispatchToAnimator) {
tryPilferPointers();
}
}
+ private boolean isAppProgressGenerationAllowed() {
+ return mBackNavigationInfo.getTouchableRegion().equals(mTouchableArea);
+ }
+
/**
* Called when a new motion event needs to be transferred to this
* {@link BackAnimationController}
@@ -536,6 +555,9 @@
// App is handling back animation. Cancel system animation latency tracking.
cancelLatencyTracking();
tryDispatchOnBackStarted(mActiveCallback, touchTracker.createStartEvent(null));
+ if (!isAppProgressGenerationAllowed()) {
+ tryPilferPointers();
+ }
}
}
@@ -642,7 +664,8 @@
private void dispatchOnBackProgressed(IOnBackInvokedCallback callback,
BackMotionEvent backEvent) {
- if (callback == null || !shouldDispatchToAnimator()) {
+ if (callback == null || (!shouldDispatchToAnimator() && mBackNavigationInfo != null
+ && isAppProgressGenerationAllowed())) {
return;
}
try {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/IPip.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/IPip.aidl
index b5f25433f..e779879 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/IPip.aidl
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/IPip.aidl
@@ -53,9 +53,11 @@
* @param destinationBounds the destination bounds the PiP window lands into
* @param overlay an optional overlay to fade out after entering PiP
* @param appBounds the bounds used to set the buffer size of the optional content overlay
+ * @param sourceRectHint the bounds to show in the transition to PiP
*/
oneway void stopSwipePipToHome(int taskId, in ComponentName componentName,
- in Rect destinationBounds, in SurfaceControl overlay, in Rect appBounds) = 2;
+ in Rect destinationBounds, in SurfaceControl overlay, in Rect appBounds,
+ in Rect sourceRectHint) = 2;
/**
* Notifies the swiping Activity to PiP onto home transition is aborted
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipUtils.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipUtils.kt
index 579a794..a09720d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipUtils.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipUtils.kt
@@ -22,6 +22,7 @@
import android.content.ComponentName
import android.content.Context
import android.content.pm.PackageManager
+import android.graphics.Rect
import android.os.RemoteException
import android.os.SystemProperties
import android.util.DisplayMetrics
@@ -138,6 +139,30 @@
}
}
+
+ /**
+ * Returns a fake source rect hint for animation purposes when app-provided one is invalid.
+ * Resulting adjusted source rect hint lets the app icon in the content overlay to stay visible.
+ */
+ @JvmStatic
+ fun getEnterPipWithOverlaySrcRectHint(appBounds: Rect, aspectRatio: Float): Rect {
+ val appBoundsAspRatio = appBounds.width().toFloat() / appBounds.height()
+ val width: Int
+ val height: Int
+ var left = 0
+ var top = 0
+ if (appBoundsAspRatio < aspectRatio) {
+ width = appBounds.width()
+ height = Math.round(width / aspectRatio)
+ top = (appBounds.height() - height) / 2
+ } else {
+ height = appBounds.height()
+ width = Math.round(height * aspectRatio)
+ left = (appBounds.width() - width) / 2
+ }
+ return Rect(left, top, left + width, top + height)
+ }
+
private var isPip2ExperimentEnabled: Boolean? = null
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/ReachabilityEduWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/ReachabilityEduWindowManager.java
index 835f1af..07082a5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/ReachabilityEduWindowManager.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/ReachabilityEduWindowManager.java
@@ -53,7 +53,7 @@
private final ShellExecutor mMainExecutor;
- private boolean mIsActivityLetterboxed;
+ private boolean mIsLetterboxDoubleTapEnabled;
private int mLetterboxVerticalPosition;
@@ -91,7 +91,7 @@
Function<Integer, Integer> disappearTimeSupplier) {
super(context, taskInfo, syncQueue, taskListener, displayLayout);
final AppCompatTaskInfo appCompatTaskInfo = taskInfo.appCompatTaskInfo;
- mIsActivityLetterboxed = appCompatTaskInfo.isLetterboxDoubleTapEnabled;
+ mIsLetterboxDoubleTapEnabled = appCompatTaskInfo.isLetterboxDoubleTapEnabled;
mLetterboxVerticalPosition = appCompatTaskInfo.topActivityLetterboxVerticalPosition;
mLetterboxHorizontalPosition = appCompatTaskInfo.topActivityLetterboxHorizontalPosition;
mTopActivityLetterboxWidth = appCompatTaskInfo.topActivityLetterboxWidth;
@@ -119,7 +119,7 @@
@Override
protected boolean eligibleToShowLayout() {
- return mIsActivityLetterboxed
+ return mIsLetterboxDoubleTapEnabled
&& (mLetterboxVerticalPosition != -1 || mLetterboxHorizontalPosition != -1);
}
@@ -142,13 +142,13 @@
@Override
public boolean updateCompatInfo(TaskInfo taskInfo, ShellTaskOrganizer.TaskListener taskListener,
boolean canShow) {
- final boolean prevIsActivityLetterboxed = mIsActivityLetterboxed;
+ final boolean prevIsLetterboxDoubleTapEnabled = mIsLetterboxDoubleTapEnabled;
final int prevLetterboxVerticalPosition = mLetterboxVerticalPosition;
final int prevLetterboxHorizontalPosition = mLetterboxHorizontalPosition;
final int prevTopActivityLetterboxWidth = mTopActivityLetterboxWidth;
final int prevTopActivityLetterboxHeight = mTopActivityLetterboxHeight;
final AppCompatTaskInfo appCompatTaskInfo = taskInfo.appCompatTaskInfo;
- mIsActivityLetterboxed = appCompatTaskInfo.isLetterboxDoubleTapEnabled;
+ mIsLetterboxDoubleTapEnabled = appCompatTaskInfo.isLetterboxDoubleTapEnabled;
mLetterboxVerticalPosition = appCompatTaskInfo.topActivityLetterboxVerticalPosition;
mLetterboxHorizontalPosition = appCompatTaskInfo.topActivityLetterboxHorizontalPosition;
mTopActivityLetterboxWidth = appCompatTaskInfo.topActivityLetterboxWidth;
@@ -162,7 +162,7 @@
mHasLetterboxSizeChanged = prevTopActivityLetterboxWidth != mTopActivityLetterboxWidth
|| prevTopActivityLetterboxHeight != mTopActivityLetterboxHeight;
- if (mHasUserDoubleTapped || prevIsActivityLetterboxed != mIsActivityLetterboxed
+ if (mHasUserDoubleTapped || prevIsLetterboxDoubleTapEnabled != mIsLetterboxDoubleTapEnabled
|| prevLetterboxVerticalPosition != mLetterboxVerticalPosition
|| prevLetterboxHorizontalPosition != mLetterboxHorizontalPosition
|| prevTopActivityLetterboxWidth != mTopActivityLetterboxWidth
@@ -249,7 +249,7 @@
&& (mLetterboxVerticalPosition == REACHABILITY_LEFT_OR_UP_POSITION
|| mLetterboxVerticalPosition == REACHABILITY_RIGHT_OR_BOTTOM_POSITION));
- if (mIsActivityLetterboxed && (eligibleForDisplayHorizontalEducation
+ if (mIsLetterboxDoubleTapEnabled && (eligibleForDisplayHorizontalEducation
|| eligibleForDisplayVerticalEducation)) {
int availableWidth = getTaskBounds().width() - mTopActivityLetterboxWidth;
int availableHeight = getTaskBounds().height() - mTopActivityLetterboxHeight;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeEventLogger.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeEventLogger.kt
index 109868d..9192e6e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeEventLogger.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeEventLogger.kt
@@ -187,7 +187,10 @@
KEYBOARD_SHORTCUT_ENTER(
FrameworkStatsLog.DESKTOP_MODE_UICHANGED__ENTER_REASON__KEYBOARD_SHORTCUT_ENTER
),
- SCREEN_ON(FrameworkStatsLog.DESKTOP_MODE_UICHANGED__ENTER_REASON__SCREEN_ON)
+ SCREEN_ON(FrameworkStatsLog.DESKTOP_MODE_UICHANGED__ENTER_REASON__SCREEN_ON),
+ APP_FROM_OVERVIEW(
+ FrameworkStatsLog.DESKTOP_MODE_UICHANGED__ENTER_REASON__APP_FROM_OVERVIEW
+ ),
}
/**
@@ -204,7 +207,7 @@
FrameworkStatsLog.DESKTOP_MODE_UICHANGED__EXIT_REASON__KEYBOARD_SHORTCUT_EXIT
),
RETURN_HOME_OR_OVERVIEW(
- FrameworkStatsLog.SPLITSCREEN_UICHANGED__EXIT_REASON__RETURN_HOME
+ FrameworkStatsLog.DESKTOP_MODE_UICHANGED__EXIT_REASON__RETURN_HOME_OR_OVERVIEW
),
TASK_FINISHED(FrameworkStatsLog.DESKTOP_MODE_UICHANGED__EXIT_REASON__TASK_FINISHED),
SCREEN_OFF(FrameworkStatsLog.DESKTOP_MODE_UICHANGED__EXIT_REASON__SCREEN_OFF)
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserver.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserver.kt
index 075e3ae..cee2d92 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserver.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserver.kt
@@ -314,8 +314,7 @@
WindowManager.TRANSIT_WAKE -> EnterReason.SCREEN_ON
Transitions.TRANSIT_DESKTOP_MODE_END_DRAG_TO_DESKTOP -> EnterReason.APP_HANDLE_DRAG
TRANSIT_ENTER_DESKTOP_FROM_APP_HANDLE_MENU_BUTTON -> EnterReason.APP_HANDLE_MENU_BUTTON
- // TODO(b/344822506): Create and update EnterReason to APP_FROM_OVERVIEW
- TRANSIT_ENTER_DESKTOP_FROM_APP_FROM_OVERVIEW -> EnterReason.UNKNOWN_ENTER
+ TRANSIT_ENTER_DESKTOP_FROM_APP_FROM_OVERVIEW -> EnterReason.APP_FROM_OVERVIEW
TRANSIT_ENTER_DESKTOP_FROM_KEYBOARD_SHORTCUT -> EnterReason.KEYBOARD_SHORTCUT_ENTER
WindowManager.TRANSIT_OPEN -> EnterReason.APP_FREEFORM_INTENT
else -> EnterReason.UNKNOWN_ENTER
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
index 57c0732..0a3c15b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
@@ -40,6 +40,7 @@
import com.android.internal.protolog.common.ProtoLog;
import com.android.launcher3.icons.IconProvider;
import com.android.wm.shell.animation.Interpolators;
+import com.android.wm.shell.common.pip.PipUtils;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.transition.Transitions;
@@ -619,19 +620,8 @@
// This is done for entering case only.
if (isInPipDirection(direction)) {
final float aspectRatio = endValue.width() / (float) endValue.height();
- if ((startValue.width() / (float) startValue.height()) > aspectRatio) {
- // use the full height.
- adjustedSourceRectHint.set(0, 0,
- (int) (startValue.height() * aspectRatio), startValue.height());
- adjustedSourceRectHint.offset(
- (startValue.width() - adjustedSourceRectHint.width()) / 2, 0);
- } else {
- // use the full width.
- adjustedSourceRectHint.set(0, 0,
- startValue.width(), (int) (startValue.width() / aspectRatio));
- adjustedSourceRectHint.offset(
- 0, (startValue.height() - adjustedSourceRectHint.height()) / 2);
- }
+ adjustedSourceRectHint.set(PipUtils.getEnterPipWithOverlaySrcRectHint(
+ startValue, aspectRatio));
}
} else {
adjustedSourceRectHint.set(sourceRectHint);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index 04dd0ef..e4420d7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -373,6 +373,10 @@
@NonNull
final Rect mAppBounds = new Rect();
+ /** The source rect hint from stopSwipePipToHome(). */
+ @Nullable
+ private Rect mSwipeSourceRectHint;
+
public PipTaskOrganizer(Context context,
@NonNull SyncTransactionQueue syncTransactionQueue,
@NonNull PipTransitionState pipTransitionState,
@@ -504,7 +508,7 @@
* Expect {@link #onTaskAppeared(ActivityManager.RunningTaskInfo, SurfaceControl)} afterwards.
*/
public void stopSwipePipToHome(int taskId, ComponentName componentName, Rect destinationBounds,
- SurfaceControl overlay, Rect appBounds) {
+ SurfaceControl overlay, Rect appBounds, Rect sourceRectHint) {
ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
"stopSwipePipToHome: %s, stat=%s", componentName, mPipTransitionState);
// do nothing if there is no startSwipePipToHome being called before
@@ -513,6 +517,7 @@
}
mPipBoundsState.setBounds(destinationBounds);
setContentOverlay(overlay, appBounds);
+ mSwipeSourceRectHint = sourceRectHint;
if (ENABLE_SHELL_TRANSITIONS && overlay != null) {
// With Shell transition, the overlay was attached to the remote transition leash, which
// will be removed when the current transition is finished, so we need to reparent it
@@ -529,6 +534,20 @@
}
}
+ /**
+ * Returns non-null Rect if the pip is entering from swipe-to-home with a specified source hint.
+ * This also consumes the rect hint.
+ */
+ @Nullable
+ Rect takeSwipeSourceRectHint() {
+ final Rect sourceRectHint = mSwipeSourceRectHint;
+ if (sourceRectHint == null || sourceRectHint.isEmpty()) {
+ return null;
+ }
+ mSwipeSourceRectHint = null;
+ return mPipTransitionState.getInSwipePipToHomeTransition() ? sourceRectHint : null;
+ }
+
private void mayRemoveContentOverlay(SurfaceControl overlay) {
final WeakReference<SurfaceControl> overlayRef = new WeakReference<>(overlay);
final long timeoutDuration = (mEnterAnimationDuration
@@ -980,7 +999,6 @@
private void onEndOfSwipePipToHomeTransition() {
if (Transitions.ENABLE_SHELL_TRANSITIONS) {
- mPipTransitionController.setEnterAnimationType(ANIM_TYPE_BOUNDS);
return;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
index 5ee6f6b..3cae72d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
@@ -1004,8 +1004,11 @@
final Rect currentBounds = pipChange.getStartAbsBounds();
int rotationDelta = deltaRotation(startRotation, endRotation);
- Rect sourceHintRect = PipBoundsAlgorithm.getValidSourceHintRect(
- taskInfo.pictureInPictureParams, currentBounds, destinationBounds);
+ Rect sourceHintRect = mPipOrganizer.takeSwipeSourceRectHint();
+ if (sourceHintRect == null) {
+ sourceHintRect = PipBoundsAlgorithm.getValidSourceHintRect(
+ taskInfo.pictureInPictureParams, currentBounds, destinationBounds);
+ }
if (rotationDelta != Surface.ROTATION_0
&& endRotation != mPipDisplayLayoutState.getRotation()) {
// Computes the destination bounds in new rotation.
@@ -1080,6 +1083,8 @@
mSurfaceTransactionHelper
.crop(finishTransaction, leash, destinationBounds)
.round(finishTransaction, leash, true /* applyCornerRadius */);
+ // Always reset to bounds animation type afterwards.
+ setEnterAnimationType(ANIM_TYPE_BOUNDS);
} else {
throw new RuntimeException("Unrecognized animation type: " + enterAnimationType);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
index de105c0..8c4bf76 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
@@ -1001,9 +1001,9 @@
}
private void stopSwipePipToHome(int taskId, ComponentName componentName, Rect destinationBounds,
- SurfaceControl overlay, Rect appBounds) {
+ SurfaceControl overlay, Rect appBounds, Rect sourceRectHint) {
mPipTaskOrganizer.stopSwipePipToHome(taskId, componentName, destinationBounds, overlay,
- appBounds);
+ appBounds, sourceRectHint);
}
private void abortSwipePipToHome(int taskId, ComponentName componentName) {
@@ -1291,13 +1291,15 @@
@Override
public void stopSwipePipToHome(int taskId, ComponentName componentName,
- Rect destinationBounds, SurfaceControl overlay, Rect appBounds) {
+ Rect destinationBounds, SurfaceControl overlay, Rect appBounds,
+ Rect sourceRectHint) {
if (overlay != null) {
overlay.setUnreleasedWarningCallSite("PipController.stopSwipePipToHome");
}
executeRemoteCallWithTaskPermission(mController, "stopSwipePipToHome",
(controller) -> controller.stopSwipePipToHome(
- taskId, componentName, destinationBounds, overlay, appBounds));
+ taskId, componentName, destinationBounds, overlay, appBounds,
+ sourceRectHint));
}
@Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/animation/PipAlphaAnimator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/animation/PipAlphaAnimator.java
index 3e298e5..895c2ae 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/animation/PipAlphaAnimator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/animation/PipAlphaAnimator.java
@@ -19,11 +19,13 @@
import android.animation.Animator;
import android.animation.ValueAnimator;
import android.annotation.IntDef;
+import android.content.Context;
import android.view.SurfaceControl;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import com.android.wm.shell.R;
import com.android.wm.shell.pip2.PipSurfaceTransactionHelper;
import java.lang.annotation.Retention;
@@ -45,6 +47,7 @@
public static final int FADE_IN = 0;
public static final int FADE_OUT = 1;
+ private final int mEnterAnimationDuration;
private final SurfaceControl mLeash;
private final SurfaceControl.Transaction mStartTransaction;
@@ -55,7 +58,8 @@
private final PipSurfaceTransactionHelper.SurfaceControlTransactionFactory
mSurfaceControlTransactionFactory;
- public PipAlphaAnimator(SurfaceControl leash,
+ public PipAlphaAnimator(Context context,
+ SurfaceControl leash,
SurfaceControl.Transaction tx,
@Fade int direction) {
mLeash = leash;
@@ -67,6 +71,9 @@
}
mSurfaceControlTransactionFactory =
new PipSurfaceTransactionHelper.VsyncSurfaceControlTransactionFactory();
+ mEnterAnimationDuration = context.getResources()
+ .getInteger(R.integer.config_pipEnterAnimationDuration);
+ setDuration(mEnterAnimationDuration);
addListener(this);
addUpdateListener(this);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java
index 1846720..fc0d36d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java
@@ -285,7 +285,8 @@
}
private void onSwipePipToHomeAnimationStart(int taskId, ComponentName componentName,
- Rect destinationBounds, SurfaceControl overlay, Rect appBounds) {
+ Rect destinationBounds, SurfaceControl overlay, Rect appBounds,
+ Rect sourceRectHint) {
ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
"onSwipePipToHomeAnimationStart: %s", componentName);
Bundle extra = new Bundle();
@@ -409,13 +410,15 @@
@Override
public void stopSwipePipToHome(int taskId, ComponentName componentName,
- Rect destinationBounds, SurfaceControl overlay, Rect appBounds) {
+ Rect destinationBounds, SurfaceControl overlay, Rect appBounds,
+ Rect sourceRectHint) {
if (overlay != null) {
overlay.setUnreleasedWarningCallSite("PipController.stopSwipePipToHome");
}
executeRemoteCallWithTaskPermission(mController, "stopSwipePipToHome",
(controller) -> controller.onSwipePipToHomeAnimationStart(
- taskId, componentName, destinationBounds, overlay, appBounds));
+ taskId, componentName, destinationBounds, overlay, appBounds,
+ sourceRectHint));
}
@Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java
index 3e215d9..0b2db6c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java
@@ -293,37 +293,32 @@
return false;
}
+ SurfaceControl overlayLeash = mPipTransitionState.getSwipePipToHomeOverlay();
PictureInPictureParams params = pipChange.getTaskInfo().pictureInPictureParams;
- Rect srcRectHint = params.getSourceRectHint();
- Rect startBounds = pipChange.getStartAbsBounds();
+
+ Rect appBounds = mPipTransitionState.getSwipePipToHomeAppBounds();
Rect destinationBounds = pipChange.getEndAbsBounds();
+ float aspectRatio = pipChange.getTaskInfo().pictureInPictureParams.getAspectRatioFloat();
+
+ // We fake the source rect hint when the one prvided by the app is invalid for
+ // the animation with an app icon overlay.
+ Rect animationSrcRectHint = overlayLeash == null ? params.getSourceRectHint()
+ : PipUtils.getEnterPipWithOverlaySrcRectHint(appBounds, aspectRatio);
+
WindowContainerTransaction finishWct = new WindowContainerTransaction();
SurfaceControl.Transaction tx = new SurfaceControl.Transaction();
- if (PipBoundsAlgorithm.isSourceRectHintValidForEnterPip(srcRectHint, destinationBounds)) {
- final float scale = (float) destinationBounds.width() / srcRectHint.width();
- startTransaction.setWindowCrop(pipLeash, srcRectHint);
- startTransaction.setPosition(pipLeash,
- destinationBounds.left - srcRectHint.left * scale,
- destinationBounds.top - srcRectHint.top * scale);
+ final float scale = (float) destinationBounds.width() / animationSrcRectHint.width();
+ startTransaction.setWindowCrop(pipLeash, animationSrcRectHint);
+ startTransaction.setPosition(pipLeash,
+ destinationBounds.left - animationSrcRectHint.left * scale,
+ destinationBounds.top - animationSrcRectHint.top * scale);
+ startTransaction.setScale(pipLeash, scale, scale);
- // Reset the scale in case we are in the multi-activity case.
- // TO_FRONT transition already scales down the task in single-activity case, but
- // in multi-activity case, reparenting yields new reset scales coming from pinned task.
- startTransaction.setScale(pipLeash, scale, scale);
- } else {
- final float scaleX = (float) destinationBounds.width() / startBounds.width();
- final float scaleY = (float) destinationBounds.height() / startBounds.height();
+ if (overlayLeash != null) {
final int overlaySize = PipContentOverlay.PipAppIconOverlay.getOverlaySize(
mPipTransitionState.getSwipePipToHomeAppBounds(), destinationBounds);
- SurfaceControl overlayLeash = mPipTransitionState.getSwipePipToHomeOverlay();
-
- startTransaction.setPosition(pipLeash, destinationBounds.left, destinationBounds.top)
- .setScale(pipLeash, scaleX, scaleY)
- .setWindowCrop(pipLeash, startBounds)
- .reparent(overlayLeash, pipLeash)
- .setLayer(overlayLeash, Integer.MAX_VALUE);
// Overlay needs to be adjusted once a new draw comes in resetting surface transform.
tx.setScale(overlayLeash, 1f, 1f);
@@ -390,15 +385,23 @@
if (pipChange == null) {
return false;
}
- // cache the PiP task token and leash
- WindowContainerToken pipTaskToken = pipChange.getContainer();
- Preconditions.checkNotNull(mPipLeash, "Leash is null for alpha transition.");
- // start transition with 0 alpha
- startTransaction.setAlpha(mPipLeash, 0f);
- PipAlphaAnimator animator = new PipAlphaAnimator(mPipLeash,
- startTransaction, PipAlphaAnimator.FADE_IN);
- animator.setAnimationEndCallback(() -> finishCallback.onTransitionFinished(null));
+ Rect destinationBounds = pipChange.getEndAbsBounds();
+ SurfaceControl pipLeash = mPipTransitionState.mPinnedTaskLeash;
+ Preconditions.checkNotNull(pipLeash, "Leash is null for alpha transition.");
+
+ // Start transition with 0 alpha at the entry bounds.
+ startTransaction.setPosition(pipLeash, destinationBounds.left, destinationBounds.top)
+ .setWindowCrop(pipLeash, destinationBounds.width(), destinationBounds.height())
+ .setAlpha(pipLeash, 0f);
+
+ PipAlphaAnimator animator = new PipAlphaAnimator(mContext, pipLeash, startTransaction,
+ PipAlphaAnimator.FADE_IN);
+ animator.setAnimationEndCallback(() -> {
+ finishCallback.onTransitionFinished(null);
+ // This should update the pip transition state accordingly after we stop playing.
+ onClientDrawAtTransitionEnd();
+ });
animator.start();
return true;
@@ -480,10 +483,10 @@
private boolean isLegacyEnter(@NonNull TransitionInfo info) {
TransitionInfo.Change pipChange = getPipChange(info);
- // If the only change in the changes list is a TO_FRONT mode PiP task,
+ // If the only change in the changes list is a opening type PiP task,
// then this is legacy-enter PiP.
- return pipChange != null && pipChange.getMode() == TRANSIT_TO_FRONT
- && info.getChanges().size() == 1;
+ return pipChange != null && info.getChanges().size() == 1
+ && (pipChange.getMode() == TRANSIT_TO_FRONT || pipChange.getMode() == TRANSIT_OPEN);
}
private boolean isRemovePipTransition(@NonNull TransitionInfo info) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index cc995ea..b6a18e5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -1524,6 +1524,7 @@
prepareExitSplitScreen(mTopStageAfterFoldDismiss, wct);
mSplitTransitions.startDismissTransition(wct, this,
mTopStageAfterFoldDismiss, EXIT_REASON_DEVICE_FOLDED);
+ setSplitsVisible(false);
} else {
exitSplitScreen(
mTopStageAfterFoldDismiss == STAGE_TYPE_MAIN ? mMainStage : mSideStage,
@@ -1893,6 +1894,10 @@
// will be canceled.
options.setPendingIntentBackgroundActivityStartMode(MODE_BACKGROUND_ACTIVITY_START_ALLOWED);
options.setPendingIntentBackgroundActivityLaunchAllowedByPermission(true);
+
+ // TODO (b/336477473): Disallow enter PiP when launching a task in split by default;
+ // this might have to be changed as more split-to-pip cujs are defined.
+ options.setDisallowEnterPictureInPictureWhileLaunching(true);
opts.putAll(options.toBundle());
}
@@ -2757,6 +2762,14 @@
// cases above and it is not already visible
return null;
} else {
+ if (triggerTask.parentTaskId == mMainStage.mRootTaskInfo.taskId
+ || triggerTask.parentTaskId == mSideStage.mRootTaskInfo.taskId) {
+ ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "handleRequest: transition=%d "
+ + "restoring to split", request.getDebugId());
+ out = new WindowContainerTransaction();
+ mSplitTransitions.setEnterTransition(transition, request.getRemoteTransition(),
+ TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE, false /* resizeAnim */);
+ }
if (isOpening && getStageOfTask(triggerTask) != null) {
ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "handleRequest: transition=%d enter split",
request.getDebugId());
@@ -3103,7 +3116,7 @@
// Includes TRANSIT_CHANGE to cover reparenting top-most task to split.
mainChild = change;
} else if (sideChild == null && stageType == STAGE_TYPE_SIDE
- && isOpeningType(change.getMode())) {
+ && (isOpeningType(change.getMode()) || change.getMode() == TRANSIT_CHANGE)) {
sideChild = change;
} else if (stageType != STAGE_TYPE_UNDEFINED && change.getMode() == TRANSIT_TO_BACK) {
// Collect all to back task's and evict them when transition finished.
@@ -3114,7 +3127,8 @@
SplitScreenTransitions.EnterSession pendingEnter = mSplitTransitions.mPendingEnter;
if (pendingEnter.mExtraTransitType
== TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE) {
- // Open to side should only be used when split already active and foregorund.
+ // Open to side should only be used when split already active and foregorund or when
+ // app is restoring to split from fullscreen.
if (mainChild == null && sideChild == null) {
Log.w(TAG, splitFailureMessage("startPendingEnterAnimation",
"Launched a task in split, but didn't receive any task in transition."));
@@ -3201,6 +3215,22 @@
mPausingTasks.clear();
});
+ if (info.getType() == TRANSIT_CHANGE && !isSplitActive()
+ && pendingEnter.mExtraTransitType == TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE) {
+ if (finalMainChild != null && finalSideChild == null) {
+ requestEnterSplitSelect(finalMainChild.getTaskInfo(),
+ new WindowContainerTransaction(),
+ getMainStagePosition(), finalMainChild.getStartAbsBounds());
+ } else if (finalSideChild != null && finalMainChild == null) {
+ requestEnterSplitSelect(finalSideChild.getTaskInfo(),
+ new WindowContainerTransaction(),
+ getSideStagePosition(), finalSideChild.getStartAbsBounds());
+ } else {
+ throw new IllegalStateException(
+ "Attempting to restore to split but reparenting change not found");
+ }
+ }
+
finishEnterSplitScreen(finishT);
addDividerBarToTransition(info, true /* show */);
return true;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
index a4ade1b..3dcdc0b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
@@ -233,32 +233,7 @@
}
if (oldRootView != mResult.mRootView) {
- if (mRelayoutParams.mLayoutResId == R.layout.desktop_mode_app_handle) {
- mWindowDecorViewHolder = new AppHandleViewHolder(
- mResult.mRootView,
- mOnCaptionTouchListener,
- mOnCaptionButtonClickListener
- );
- } else if (mRelayoutParams.mLayoutResId
- == R.layout.desktop_mode_app_header) {
- loadAppInfoIfNeeded();
- mWindowDecorViewHolder = new AppHeaderViewHolder(
- mResult.mRootView,
- mOnCaptionTouchListener,
- mOnCaptionButtonClickListener,
- mOnCaptionLongClickListener,
- mOnCaptionGenericMotionListener,
- mAppName,
- mAppIconBitmap,
- () -> {
- if (!isMaximizeMenuActive()) {
- createMaximizeMenu();
- }
- return Unit.INSTANCE;
- });
- } else {
- throw new IllegalArgumentException("Unexpected layout resource id");
- }
+ mWindowDecorViewHolder = createViewHolder();
}
Trace.beginSection("DesktopModeWindowDecoration#relayout-binding");
mWindowDecorViewHolder.bindData(mTaskInfo);
@@ -269,16 +244,18 @@
closeMaximizeMenu();
}
- final boolean isFreeform =
- taskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM;
- final boolean isDragResizeable = isFreeform && taskInfo.isResizeable;
- if (!isDragResizeable) {
+ updateDragResizeListener(oldDecorationSurface);
+ updateMaximizeMenu(startT);
+ Trace.endSection(); // DesktopModeWindowDecoration#relayout
+ }
+
+ private void updateDragResizeListener(SurfaceControl oldDecorationSurface) {
+ if (!isDragResizable(mTaskInfo)) {
if (!mTaskInfo.positionInParent.equals(mPositionInParent)) {
// We still want to track caption bar's exclusion region on a non-resizeable task.
updateExclusionRegion();
}
closeDragResizeListener();
- Trace.endSection(); // DesktopModeWindowDecoration#relayout
return;
}
@@ -312,15 +289,51 @@
|| !mTaskInfo.positionInParent.equals(mPositionInParent)) {
updateExclusionRegion();
}
+ }
- if (isMaximizeMenuActive()) {
- if (!mTaskInfo.isVisible()) {
- closeMaximizeMenu();
- } else {
- mMaximizeMenu.positionMenu(calculateMaximizeMenuPosition(), startT);
- }
+ private static boolean isDragResizable(ActivityManager.RunningTaskInfo taskInfo) {
+ final boolean isFreeform =
+ taskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM;
+ return isFreeform && taskInfo.isResizeable;
+ }
+
+ private void updateMaximizeMenu(SurfaceControl.Transaction startT) {
+ if (!isDragResizable(mTaskInfo) || !isMaximizeMenuActive()) {
+ return;
}
- Trace.endSection(); // DesktopModeWindowDecoration#relayout
+ if (!mTaskInfo.isVisible()) {
+ closeMaximizeMenu();
+ } else {
+ mMaximizeMenu.positionMenu(calculateMaximizeMenuPosition(), startT);
+ }
+ }
+
+ private WindowDecorationViewHolder createViewHolder() {
+ if (mRelayoutParams.mLayoutResId == R.layout.desktop_mode_app_handle) {
+ return new AppHandleViewHolder(
+ mResult.mRootView,
+ mOnCaptionTouchListener,
+ mOnCaptionButtonClickListener
+ );
+ } else if (mRelayoutParams.mLayoutResId
+ == R.layout.desktop_mode_app_header) {
+ loadAppInfoIfNeeded();
+ return new AppHeaderViewHolder(
+ mResult.mRootView,
+ mOnCaptionTouchListener,
+ mOnCaptionButtonClickListener,
+ mOnCaptionLongClickListener,
+ mOnCaptionGenericMotionListener,
+ mAppName,
+ mAppIconBitmap,
+ () -> {
+ if (!isMaximizeMenuActive()) {
+ createMaximizeMenu();
+ }
+ return Unit.INSTANCE;
+ });
+ }
+ throw new IllegalArgumentException("Unexpected layout resource id");
}
@VisibleForTesting
@@ -818,12 +831,12 @@
// We want handle to remain pressed if the pointer moves outside of it during a drag.
handle.setPressed((inHandle && action == ACTION_DOWN)
|| (handle.isPressed() && action != ACTION_UP && action != ACTION_CANCEL));
- if (isHandleMenuActive() && !isMenuAboveStatusBar()) {
+ if (isHandleMenuActive() && !isHandleMenuAboveStatusBar()) {
mHandleMenu.checkMotionEvent(ev);
}
}
- private boolean isMenuAboveStatusBar() {
+ private boolean isHandleMenuAboveStatusBar() {
return Flags.enableAdditionalWindowsAboveStatusBar() && !mTaskInfo.isFreeform();
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.java
index bfc4e0d..df0836c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.java
@@ -24,6 +24,7 @@
import static android.view.MotionEvent.ACTION_UP;
import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
+import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -35,6 +36,7 @@
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Color;
+import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.Rect;
import android.view.MotionEvent;
@@ -70,8 +72,14 @@
private final DesktopModeWindowDecoration mParentDecor;
@VisibleForTesting
AdditionalViewContainer mHandleMenuViewContainer;
+ // Position of the handle menu used for laying out the handle view.
@VisibleForTesting
final PointF mHandleMenuPosition = new PointF();
+ // With the introduction of {@link AdditionalSystemViewContainer}, {@link mHandleMenuPosition}
+ // may be in a different coordinate space than the input coordinates. Therefore, we still care
+ // about the menu's coordinates relative to the display as a whole, so we need to maintain
+ // those as well.
+ final Point mGlobalMenuPosition = new Point();
private final boolean mShouldShowWindowingPill;
private final Bitmap mAppIconBitmap;
private final CharSequence mAppName;
@@ -244,39 +252,23 @@
private void updateHandleMenuPillPositions() {
int menuX;
final int menuY;
+ final Rect taskBounds = mTaskInfo.getConfiguration().windowConfiguration.getBounds();
+ updateGlobalMenuPosition(taskBounds);
if (mLayoutResId == R.layout.desktop_mode_app_header) {
// Align the handle menu to the left side of the caption.
menuX = mMarginMenuStart;
menuY = mMarginMenuTop;
} else {
- final int handleWidth = loadDimensionPixelSize(mContext.getResources(),
- R.dimen.desktop_mode_fullscreen_decor_caption_width);
- final int handleOffset = (mMenuWidth / 2) - (handleWidth / 2);
- final int captionX = mParentDecor.getCaptionX();
- // TODO(b/343561161): This needs to be calculated differently if the task is in
- // top/bottom split.
if (Flags.enableAdditionalWindowsAboveStatusBar()) {
- final Rect leftOrTopStageBounds = new Rect();
- if (mSplitScreenController.getSplitPosition(mTaskInfo.taskId)
- == SPLIT_POSITION_BOTTOM_OR_RIGHT) {
- mSplitScreenController.getStageBounds(leftOrTopStageBounds, new Rect());
- }
// In a focused decor, we use global coordinates for handle menu. Therefore we
// need to account for other factors like split stage and menu/handle width to
// center the menu.
final DisplayLayout layout = mDisplayController
.getDisplayLayout(mTaskInfo.displayId);
- menuX = captionX + handleOffset - (layout.width() / 2);
- if (mSplitScreenController.getSplitPosition(mTaskInfo.taskId)
- == SPLIT_POSITION_BOTTOM_OR_RIGHT && layout.isLandscape()) {
- // If this task in the right stage, we need to offset by left stage's width
- menuX += leftOrTopStageBounds.width();
- }
- menuY = mMarginMenuStart - ((layout.height() - mMenuHeight) / 2);
+ menuX = mGlobalMenuPosition.x + ((mMenuWidth - layout.width()) / 2);
+ menuY = mGlobalMenuPosition.y + ((mMenuHeight - layout.height()) / 2);
} else {
- final int captionWidth = mTaskInfo.getConfiguration()
- .windowConfiguration.getBounds().width();
- menuX = (captionWidth / 2) - (mMenuWidth / 2);
+ menuX = (taskBounds.width() / 2) - (mMenuWidth / 2);
menuY = mMarginMenuTop;
}
}
@@ -284,6 +276,36 @@
mHandleMenuPosition.set(menuX, menuY);
}
+ private void updateGlobalMenuPosition(Rect taskBounds) {
+ if (mTaskInfo.isFreeform()) {
+ mGlobalMenuPosition.set(taskBounds.left + mMarginMenuStart,
+ taskBounds.top + mMarginMenuTop);
+ } else if (mTaskInfo.getWindowingMode() == WINDOWING_MODE_FULLSCREEN) {
+ mGlobalMenuPosition.set(
+ (taskBounds.width() / 2) - (mMenuWidth / 2) + mMarginMenuStart,
+ mMarginMenuTop
+ );
+ } else if (mTaskInfo.getWindowingMode() == WINDOWING_MODE_MULTI_WINDOW) {
+ final int splitPosition = mSplitScreenController.getSplitPosition(mTaskInfo.taskId);
+ final Rect leftOrTopStageBounds = new Rect();
+ final Rect rightOrBottomStageBounds = new Rect();
+ mSplitScreenController.getStageBounds(leftOrTopStageBounds,
+ rightOrBottomStageBounds);
+ // TODO(b/343561161): This needs to be calculated differently if the task is in
+ // top/bottom split.
+ if (splitPosition == SPLIT_POSITION_BOTTOM_OR_RIGHT) {
+ mGlobalMenuPosition.set(leftOrTopStageBounds.width()
+ + (rightOrBottomStageBounds.width() / 2)
+ - (mMenuWidth / 2) + mMarginMenuStart,
+ mMarginMenuTop);
+ } else if (splitPosition == SPLIT_POSITION_TOP_OR_LEFT) {
+ mGlobalMenuPosition.set((leftOrTopStageBounds.width() / 2)
+ - (mMenuWidth / 2) + mMarginMenuStart,
+ mMarginMenuTop);
+ }
+ }
+ }
+
/**
* Update pill layout, in case task changes have caused positioning to change.
*/
@@ -302,6 +324,8 @@
* @param ev the MotionEvent to compare against.
*/
void checkMotionEvent(MotionEvent ev) {
+ // If the menu view is above status bar, we can let the views handle input directly.
+ if (isViewAboveStatusBar()) return;
final View handleMenu = mHandleMenuViewContainer.getView();
final HandleMenuImageButton collapse = handleMenu.findViewById(R.id.collapse_menu_button);
final PointF inputPoint = translateInputToLocalSpace(ev);
@@ -314,6 +338,11 @@
}
}
+ private boolean isViewAboveStatusBar() {
+ return Flags.enableAdditionalWindowsAboveStatusBar()
+ && !mTaskInfo.isFreeform();
+ }
+
// Translate the input point from display coordinates to the same space as the handle menu.
private PointF translateInputToLocalSpace(MotionEvent ev) {
return new PointF(ev.getX() - mHandleMenuPosition.x,
@@ -329,10 +358,33 @@
*/
boolean isValidMenuInput(PointF inputPoint) {
if (!viewsLaidOut()) return true;
- return pointInView(
- mHandleMenuViewContainer.getView(),
- inputPoint.x - mHandleMenuPosition.x,
- inputPoint.y - mHandleMenuPosition.y);
+ if (!isViewAboveStatusBar()) {
+ return pointInView(
+ mHandleMenuViewContainer.getView(),
+ inputPoint.x - mHandleMenuPosition.x,
+ inputPoint.y - mHandleMenuPosition.y);
+ } else {
+ // Handle menu exists in a different coordinate space when added to WindowManager.
+ // Therefore we must compare the provided input coordinates to global menu coordinates.
+ // This includes factoring for split stage as input coordinates are relative to split
+ // stage position, not relative to the display as a whole.
+ PointF inputRelativeToMenu = new PointF(
+ inputPoint.x - mGlobalMenuPosition.x,
+ inputPoint.y - mGlobalMenuPosition.y
+ );
+ if (mSplitScreenController.getSplitPosition(mTaskInfo.taskId)
+ == SPLIT_POSITION_BOTTOM_OR_RIGHT) {
+ // TODO(b/343561161): This also needs to be calculated differently if
+ // the task is in top/bottom split.
+ Rect leftStageBounds = new Rect();
+ mSplitScreenController.getStageBounds(leftStageBounds, new Rect());
+ inputRelativeToMenu.x += leftStageBounds.width();
+ }
+ return pointInView(
+ mHandleMenuViewContainer.getView(),
+ inputRelativeToMenu.x,
+ inputRelativeToMenu.y);
+ }
}
private boolean pointInView(View v, float x, float y) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
index a08f97c..b9532dd 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
@@ -213,13 +213,39 @@
return;
}
+ inflateIfNeeded(params, wct, rootView, oldLayoutResId, outResult);
+ if (outResult.mRootView == null) {
+ // Didn't manage to create a root view, early out.
+ return;
+ }
+ rootView = null; // Clear it just in case we use it accidentally
+
+ updateCaptionVisibility(outResult.mRootView, mTaskInfo.displayId);
+
+ final Rect taskBounds = mTaskInfo.getConfiguration().windowConfiguration.getBounds();
+ outResult.mWidth = taskBounds.width();
+ outResult.mHeight = taskBounds.height();
+ outResult.mRootView.setTaskFocusState(mTaskInfo.isFocused);
+ final Resources resources = mDecorWindowContext.getResources();
+ outResult.mCaptionHeight = loadDimensionPixelSize(resources, params.mCaptionHeightId);
+ outResult.mCaptionWidth = params.mCaptionWidthId != Resources.ID_NULL
+ ? loadDimensionPixelSize(resources, params.mCaptionWidthId) : taskBounds.width();
+ outResult.mCaptionX = (outResult.mWidth - outResult.mCaptionWidth) / 2;
+
+ updateDecorationContainerSurface(startT, outResult);
+ updateCaptionContainerSurface(startT, outResult);
+ updateCaptionInsets(params, wct, outResult, taskBounds);
+ updateTaskSurface(params, startT, finishT, outResult);
+ updateViewHost(params, startT, outResult);
+ }
+
+ private void inflateIfNeeded(RelayoutParams params, WindowContainerTransaction wct,
+ T rootView, int oldLayoutResId, RelayoutResult<T> outResult) {
if (rootView == null && params.mLayoutResId == 0) {
throw new IllegalArgumentException("layoutResId and rootView can't both be invalid.");
}
outResult.mRootView = rootView;
- rootView = null; // Clear it just in case we use it accidentally
-
final int oldDensityDpi = mWindowDecorConfig != null
? mWindowDecorConfig.densityDpi : DENSITY_DPI_UNDEFINED;
final int oldNightMode = mWindowDecorConfig != null
@@ -253,25 +279,17 @@
outResult.mRootView = (T) LayoutInflater.from(mDecorWindowContext)
.inflate(params.mLayoutResId, null);
}
+ }
- updateCaptionVisibility(outResult.mRootView, mTaskInfo.displayId);
-
- final Resources resources = mDecorWindowContext.getResources();
- final Configuration taskConfig = mTaskInfo.getConfiguration();
- final Rect taskBounds = taskConfig.windowConfiguration.getBounds();
- final boolean isFullscreen = taskConfig.windowConfiguration.getWindowingMode()
- == WINDOWING_MODE_FULLSCREEN;
- outResult.mWidth = taskBounds.width();
- outResult.mHeight = taskBounds.height();
-
- // DecorationContainerSurface
+ private void updateDecorationContainerSurface(
+ SurfaceControl.Transaction startT, RelayoutResult<T> outResult) {
if (mDecorationContainerSurface == null) {
final SurfaceControl.Builder builder = mSurfaceControlBuilderSupplier.get();
mDecorationContainerSurface = builder
.setName("Decor container of Task=" + mTaskInfo.taskId)
.setContainerLayer()
.setParent(mTaskSurface)
- .setCallsite("WindowDecoration.relayout_1")
+ .setCallsite("WindowDecoration.updateDecorationContainerSurface")
.build();
startT.setTrustedOverlay(mDecorationContainerSurface, true)
@@ -281,101 +299,101 @@
startT.setWindowCrop(mDecorationContainerSurface, outResult.mWidth, outResult.mHeight)
.show(mDecorationContainerSurface);
+ }
- // CaptionContainerSurface, CaptionWindowManager
+ private void updateCaptionContainerSurface(
+ SurfaceControl.Transaction startT, RelayoutResult<T> outResult) {
if (mCaptionContainerSurface == null) {
final SurfaceControl.Builder builder = mSurfaceControlBuilderSupplier.get();
mCaptionContainerSurface = builder
.setName("Caption container of Task=" + mTaskInfo.taskId)
.setContainerLayer()
.setParent(mDecorationContainerSurface)
- .setCallsite("WindowDecoration.relayout_2")
+ .setCallsite("WindowDecoration.updateCaptionContainerSurface")
.build();
}
- outResult.mCaptionHeight = loadDimensionPixelSize(resources, params.mCaptionHeightId);
- outResult.mCaptionWidth = params.mCaptionWidthId != Resources.ID_NULL
- ? loadDimensionPixelSize(resources, params.mCaptionWidthId) : taskBounds.width();
- outResult.mCaptionX = (outResult.mWidth - outResult.mCaptionWidth) / 2;
-
startT.setWindowCrop(mCaptionContainerSurface, outResult.mCaptionWidth,
outResult.mCaptionHeight)
.setPosition(mCaptionContainerSurface, outResult.mCaptionX, 0 /* y */)
.setLayer(mCaptionContainerSurface, CAPTION_LAYER_Z_ORDER)
.show(mCaptionContainerSurface);
+ }
- outResult.mRootView.setTaskFocusState(mTaskInfo.isFocused);
-
- // Caption insets
- if (mIsCaptionVisible) {
- // Caption inset is the full width of the task with the |captionHeight| and
- // positioned at the top of the task bounds, also in absolute coordinates.
- // So just reuse the task bounds and adjust the bottom coordinate.
- final Rect captionInsetsRect = new Rect(taskBounds);
- captionInsetsRect.bottom = captionInsetsRect.top + outResult.mCaptionHeight;
-
- // Caption bounding rectangles: these are optional, and are used to present finer
- // insets than traditional |Insets| to apps about where their content is occluded.
- // These are also in absolute coordinates.
- final Rect[] boundingRects;
- final int numOfElements = params.mOccludingCaptionElements.size();
- if (numOfElements == 0) {
- boundingRects = null;
- } else {
- // The customizable region can at most be equal to the caption bar.
- if (params.hasInputFeatureSpy()) {
- outResult.mCustomizableCaptionRegion.set(captionInsetsRect);
- }
- boundingRects = new Rect[numOfElements];
- for (int i = 0; i < numOfElements; i++) {
- final OccludingCaptionElement element =
- params.mOccludingCaptionElements.get(i);
- final int elementWidthPx =
- resources.getDimensionPixelSize(element.mWidthResId);
- boundingRects[i] =
- calculateBoundingRect(element, elementWidthPx, captionInsetsRect);
- // Subtract the regions used by the caption elements, the rest is
- // customizable.
- if (params.hasInputFeatureSpy()) {
- outResult.mCustomizableCaptionRegion.op(boundingRects[i],
- Region.Op.DIFFERENCE);
- }
- }
- }
-
- final WindowDecorationInsets newInsets = new WindowDecorationInsets(
- mTaskInfo.token, mOwner, captionInsetsRect, boundingRects);
- if (!newInsets.equals(mWindowDecorationInsets)) {
- // Add or update this caption as an insets source.
- mWindowDecorationInsets = newInsets;
- mWindowDecorationInsets.addOrUpdate(wct);
- }
- } else {
+ private void updateCaptionInsets(RelayoutParams params, WindowContainerTransaction wct,
+ RelayoutResult<T> outResult, Rect taskBounds) {
+ if (!mIsCaptionVisible) {
if (mWindowDecorationInsets != null) {
mWindowDecorationInsets.remove(wct);
mWindowDecorationInsets = null;
}
+ return;
}
+ // Caption inset is the full width of the task with the |captionHeight| and
+ // positioned at the top of the task bounds, also in absolute coordinates.
+ // So just reuse the task bounds and adjust the bottom coordinate.
+ final Rect captionInsetsRect = new Rect(taskBounds);
+ captionInsetsRect.bottom = captionInsetsRect.top + outResult.mCaptionHeight;
- // Task surface itself
- float shadowRadius;
- final Point taskPosition = mTaskInfo.positionInParent;
- if (isFullscreen) {
- // Shadow is not needed for fullscreen tasks
- shadowRadius = 0;
+ // Caption bounding rectangles: these are optional, and are used to present finer
+ // insets than traditional |Insets| to apps about where their content is occluded.
+ // These are also in absolute coordinates.
+ final Rect[] boundingRects;
+ final int numOfElements = params.mOccludingCaptionElements.size();
+ if (numOfElements == 0) {
+ boundingRects = null;
} else {
- shadowRadius = loadDimension(resources, params.mShadowRadiusId);
+ // The customizable region can at most be equal to the caption bar.
+ if (params.hasInputFeatureSpy()) {
+ outResult.mCustomizableCaptionRegion.set(captionInsetsRect);
+ }
+ final Resources resources = mDecorWindowContext.getResources();
+ boundingRects = new Rect[numOfElements];
+ for (int i = 0; i < numOfElements; i++) {
+ final OccludingCaptionElement element =
+ params.mOccludingCaptionElements.get(i);
+ final int elementWidthPx =
+ resources.getDimensionPixelSize(element.mWidthResId);
+ boundingRects[i] =
+ calculateBoundingRect(element, elementWidthPx, captionInsetsRect);
+ // Subtract the regions used by the caption elements, the rest is
+ // customizable.
+ if (params.hasInputFeatureSpy()) {
+ outResult.mCustomizableCaptionRegion.op(boundingRects[i],
+ Region.Op.DIFFERENCE);
+ }
+ }
}
+ final WindowDecorationInsets newInsets = new WindowDecorationInsets(
+ mTaskInfo.token, mOwner, captionInsetsRect, boundingRects);
+ if (!newInsets.equals(mWindowDecorationInsets)) {
+ // Add or update this caption as an insets source.
+ mWindowDecorationInsets = newInsets;
+ mWindowDecorationInsets.addOrUpdate(wct);
+ }
+ }
+
+ private void updateTaskSurface(RelayoutParams params, SurfaceControl.Transaction startT,
+ SurfaceControl.Transaction finishT, RelayoutResult<T> outResult) {
if (params.mSetTaskPositionAndCrop) {
+ final Point taskPosition = mTaskInfo.positionInParent;
startT.setWindowCrop(mTaskSurface, outResult.mWidth, outResult.mHeight);
finishT.setWindowCrop(mTaskSurface, outResult.mWidth, outResult.mHeight)
.setPosition(mTaskSurface, taskPosition.x, taskPosition.y);
}
- startT.setShadowRadius(mTaskSurface, shadowRadius)
- .show(mTaskSurface);
+ float shadowRadius;
+ if (mTaskInfo.getWindowingMode() == WINDOWING_MODE_FULLSCREEN) {
+ // Shadow is not needed for fullscreen tasks
+ shadowRadius = 0;
+ } else {
+ shadowRadius =
+ loadDimension(mDecorWindowContext.getResources(), params.mShadowRadiusId);
+ }
+ startT.setShadowRadius(mTaskSurface, shadowRadius).show(mTaskSurface);
finishT.setShadowRadius(mTaskSurface, shadowRadius);
+
if (mTaskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM) {
if (!DesktopModeStatus.isVeiledResizeEnabled()) {
// When fluid resize is enabled, add a background to freeform tasks
@@ -390,7 +408,10 @@
} else if (!DesktopModeStatus.isVeiledResizeEnabled()) {
startT.unsetColor(mTaskSurface);
}
+ }
+ private void updateViewHost(RelayoutParams params, SurfaceControl.Transaction onDrawTransaction,
+ RelayoutResult<T> outResult) {
Trace.beginSection("CaptionViewHostLayout");
if (mCaptionWindowManager == null) {
// Put caption under a container surface because ViewRootImpl sets the destination frame
@@ -399,9 +420,7 @@
mTaskInfo.getConfiguration(), mCaptionContainerSurface,
null /* hostInputToken */);
}
-
- // Caption view
- mCaptionWindowManager.setConfiguration(taskConfig);
+ mCaptionWindowManager.setConfiguration(mTaskInfo.getConfiguration());
final WindowManager.LayoutParams lp =
new WindowManager.LayoutParams(outResult.mCaptionWidth, outResult.mCaptionHeight,
TYPE_APPLICATION,
@@ -414,14 +433,14 @@
mViewHost = mSurfaceControlViewHostFactory.create(mDecorWindowContext, mDisplay,
mCaptionWindowManager);
if (params.mApplyStartTransactionOnDraw) {
- mViewHost.getRootSurfaceControl().applyTransactionOnDraw(startT);
+ mViewHost.getRootSurfaceControl().applyTransactionOnDraw(onDrawTransaction);
}
mViewHost.setView(outResult.mRootView, lp);
Trace.endSection();
} else {
Trace.beginSection("CaptionViewHostLayout-relayout");
if (params.mApplyStartTransactionOnDraw) {
- mViewHost.getRootSurfaceControl().applyTransactionOnDraw(startT);
+ mViewHost.getRootSurfaceControl().applyTransactionOnDraw(onDrawTransaction);
}
mViewHost.relayout(lp);
Trace.endSection();
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 f6f3aa4..1903586 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
@@ -123,6 +123,7 @@
private DefaultCrossActivityBackAnimation mDefaultCrossActivityBackAnimation;
private CrossTaskBackAnimation mCrossTaskBackAnimation;
private ShellBackAnimationRegistry mShellBackAnimationRegistry;
+ private Rect mTouchableRegion;
@Before
public void setUp() throws Exception {
@@ -158,6 +159,8 @@
mShellCommandHandler);
mShellInit.init();
mShellExecutor.flushAll();
+ mTouchableRegion = new Rect(0, 0, 100, 100);
+ mController.mTouchableArea.set(mTouchableRegion);
}
private void createNavigationInfo(int backType,
@@ -169,7 +172,8 @@
.setOnBackNavigationDone(new RemoteCallback((bundle) -> {}))
.setOnBackInvokedCallback(mAppCallback)
.setPrepareRemoteAnimation(enableAnimation)
- .setAnimationCallback(isAnimationCallback);
+ .setAnimationCallback(isAnimationCallback)
+ .setTouchableRegion(mTouchableRegion);
createNavigationInfo(builder);
}
@@ -234,7 +238,8 @@
.setType(type)
.setOnBackInvokedCallback(mAppCallback)
.setPrepareRemoteAnimation(true)
- .setOnBackNavigationDone(new RemoteCallback(result)));
+ .setOnBackNavigationDone(new RemoteCallback(result))
+ .setTouchableRegion(mTouchableRegion));
triggerBackGesture();
simulateRemoteAnimationStart();
mShellExecutor.flushAll();
@@ -512,7 +517,8 @@
.setType(type)
.setOnBackInvokedCallback(mAppCallback)
.setPrepareRemoteAnimation(true)
- .setOnBackNavigationDone(new RemoteCallback(result)));
+ .setOnBackNavigationDone(new RemoteCallback(result))
+ .setTouchableRegion(mTouchableRegion));
triggerBackGesture();
simulateRemoteAnimationStart();
mShellExecutor.flushAll();
@@ -543,7 +549,8 @@
createNavigationInfo(new BackNavigationInfo.Builder()
.setType(type)
.setOnBackInvokedCallback(mAppCallback)
- .setOnBackNavigationDone(new RemoteCallback(result)));
+ .setOnBackNavigationDone(new RemoteCallback(result))
+ .setTouchableRegion(mTouchableRegion));
triggerBackGesture();
mShellExecutor.flushAll();
releaseBackGesture();
@@ -570,7 +577,8 @@
createNavigationInfo(new BackNavigationInfo.Builder()
.setType(type)
.setOnBackInvokedCallback(mAppCallback)
- .setOnBackNavigationDone(new RemoteCallback(result)));
+ .setOnBackNavigationDone(new RemoteCallback(result))
+ .setTouchableRegion(mTouchableRegion));
doMotionEvent(MotionEvent.ACTION_CANCEL, 0);
mShellExecutor.flushAll();
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserverTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserverTest.kt
index 7122181..5f6132a 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserverTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserverTest.kt
@@ -187,7 +187,6 @@
}
@Test
- // TODO(b/344822506): Update test when we add enter reason for app from overview
fun transitEnterDesktopFromAppFromOverview_logTaskAddedAndEnterReasonUnknown() {
val change = createChange(TRANSIT_TO_FRONT, createTaskInfo(1, WINDOWING_MODE_FREEFORM))
val transitionInfo =
@@ -200,7 +199,7 @@
assertThat(sessionId).isNotNull()
verify(desktopModeEventLogger, times(1))
- .logSessionEnter(eq(sessionId!!), eq(EnterReason.UNKNOWN_ENTER))
+ .logSessionEnter(eq(sessionId!!), eq(EnterReason.APP_FROM_OVERVIEW))
verify(desktopModeEventLogger, times(1)).logTaskAdded(eq(sessionId), any())
verifyZeroInteractions(desktopModeEventLogger)
}
diff --git a/libs/hwui/jni/Graphics.cpp b/libs/hwui/jni/Graphics.cpp
index 07e97f8..a88139d 100644
--- a/libs/hwui/jni/Graphics.cpp
+++ b/libs/hwui/jni/Graphics.cpp
@@ -583,6 +583,16 @@
transferParams.a, transferParams.b, transferParams.c, transferParams.d,
transferParams.e, transferParams.f, transferParams.g);
+ // Some transfer functions that are considered valid by Skia are not
+ // accepted by android.graphics.
+ if (hasException(env)) {
+ // Callers (e.g. Bitmap#getColorSpace) are not expected to throw an
+ // Exception, so clear it and return null, which is a documented
+ // possibility.
+ env->ExceptionClear();
+ return nullptr;
+ }
+
jfloatArray xyzArray = env->NewFloatArray(9);
jfloat xyz[9] = {
xyzMatrix.vals[0][0],
diff --git a/location/lib/java/com/android/location/provider/SignificantPlaceProvider.java b/location/lib/java/com/android/location/provider/SignificantPlaceProvider.java
index 0b39a9a..df4b903 100644
--- a/location/lib/java/com/android/location/provider/SignificantPlaceProvider.java
+++ b/location/lib/java/com/android/location/provider/SignificantPlaceProvider.java
@@ -21,17 +21,22 @@
import android.hardware.location.ISignificantPlaceProvider;
import android.hardware.location.ISignificantPlaceProviderManager;
import android.os.Binder;
+import android.os.Handler;
import android.os.IBinder;
+import android.os.Looper;
import android.os.Process;
import android.os.RemoteException;
+import android.util.Log;
import com.android.internal.annotations.GuardedBy;
/** @hide */
-public class SignificantPlaceProvider {
+public abstract class SignificantPlaceProvider {
public static final String ACTION = TrustManager.ACTION_BIND_SIGNIFICANT_PLACE_PROVIDER;
+ private static final String TAG = "SignificantPlaceProvider";
+
private final IBinder mBinder;
// write locked on mBinder, read lock is optional depending on atomicity requirements
@@ -69,6 +74,9 @@
}
}
+ /** Invoked when some client has checked whether the device is in a significant place. */
+ public abstract void onSignificantPlaceCheck();
+
private final class Service extends ISignificantPlaceProvider.Stub {
Service() {}
@@ -76,7 +84,7 @@
@Override
public void setSignificantPlaceProviderManager(ISignificantPlaceProviderManager manager) {
if (Binder.getCallingUid() != Process.SYSTEM_UID) {
- return;
+ throw new SecurityException();
}
synchronized (mBinder) {
@@ -91,5 +99,22 @@
mManager = manager;
}
}
+
+ @Override
+ public void onSignificantPlaceCheck() {
+ if (Binder.getCallingUid() != Process.SYSTEM_UID) {
+ throw new SecurityException();
+ }
+
+ try {
+ SignificantPlaceProvider.this.onSignificantPlaceCheck();
+ } catch (RuntimeException e) {
+ // exceptions on one-way binder threads are dropped - move to a different thread
+ Log.w(TAG, e);
+ new Handler(Looper.getMainLooper()).post(() -> {
+ throw new AssertionError(e);
+ });
+ }
+ }
}
}
diff --git a/media/java/android/media/tv/ITvInputService.aidl b/media/java/android/media/tv/ITvInputService.aidl
old mode 100755
new mode 100644
diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppManager.java b/media/java/android/media/tv/interactive/TvInteractiveAppManager.java
old mode 100755
new mode 100644
diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppService.java b/media/java/android/media/tv/interactive/TvInteractiveAppService.java
old mode 100755
new mode 100644
diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppView.java b/media/java/android/media/tv/interactive/TvInteractiveAppView.java
old mode 100755
new mode 100644
diff --git a/media/java/android/mtp/MtpDatabase.java b/media/java/android/mtp/MtpDatabase.java
old mode 100755
new mode 100644
diff --git a/native/android/input.cpp b/native/android/input.cpp
index 0a22314..9a8cda3 100644
--- a/native/android/input.cpp
+++ b/native/android/input.cpp
@@ -100,7 +100,8 @@
}
int32_t AMotionEvent_getFlags(const AInputEvent* motion_event) {
- return static_cast<const MotionEvent*>(motion_event)->getFlags();
+ return static_cast<const MotionEvent*>(motion_event)->getFlags() &
+ ~AMOTION_EVENT_PRIVATE_FLAG_MASK;
}
int32_t AMotionEvent_getMetaState(const AInputEvent* motion_event) {
diff --git a/native/android/performance_hint.cpp b/native/android/performance_hint.cpp
index 02d72ad..44fa677 100644
--- a/native/android/performance_hint.cpp
+++ b/native/android/performance_hint.cpp
@@ -51,6 +51,9 @@
constexpr int64_t SEND_HINT_TIMEOUT = std::chrono::nanoseconds(100ms).count();
struct AWorkDuration : public hal::WorkDuration {};
+// Shared lock for the whole PerformanceHintManager and sessions
+static std::mutex sHintMutex = std::mutex{};
+
struct APerformanceHintManager {
public:
static APerformanceHintManager* getInstance();
@@ -192,6 +195,7 @@
}
auto out = new APerformanceHintSession(mHintManager, std::move(session), mPreferredRateNanos,
initialTargetWorkDurationNanos, sessionConfig);
+ std::scoped_lock lock(sHintMutex);
out->traceThreads(tids);
out->traceTargetDuration(initialTargetWorkDurationNanos);
out->tracePowerEfficient(false);
@@ -219,6 +223,7 @@
if (sessionConfig->id > INT32_MAX) {
ALOGE("Session ID too large, must fit 32-bit integer");
}
+ std::scoped_lock lock(sHintMutex);
constexpr int numEnums =
ndk::enum_range<hal::SessionHint>().end() - ndk::enum_range<hal::SessionHint>().begin();
mLastHintSentTimestamp = std::vector<int64_t>(numEnums, 0);
@@ -244,6 +249,7 @@
ret.getMessage());
return EPIPE;
}
+ std::scoped_lock lock(sHintMutex);
mTargetDurationNanos = targetDurationNanos;
/**
* Most of the workload is target_duration dependent, so now clear the cached samples
@@ -267,6 +273,7 @@
}
int APerformanceHintSession::sendHint(SessionHint hint) {
+ std::scoped_lock lock(sHintMutex);
if (hint < 0 || hint >= static_cast<int32_t>(mLastHintSentTimestamp.size())) {
ALOGE("%s: invalid session hint %d", __FUNCTION__, hint);
return EINVAL;
@@ -305,6 +312,7 @@
return EPIPE;
}
+ std::scoped_lock lock(sHintMutex);
traceThreads(tids);
return 0;
@@ -343,6 +351,7 @@
ret.getMessage());
return EPIPE;
}
+ std::scoped_lock lock(sHintMutex);
tracePowerEfficient(enabled);
return OK;
}
@@ -355,6 +364,7 @@
int64_t actualTotalDurationNanos = workDuration->durationNanos;
int64_t now = uptimeNanos();
workDuration->timeStampNanos = now;
+ std::scoped_lock lock(sHintMutex);
traceActualDuration(workDuration->durationNanos);
mActualWorkDurations.push_back(std::move(*workDuration));
diff --git a/native/graphics/jni/Android.bp b/native/graphics/jni/Android.bp
index 8ea4632..746c280 100644
--- a/native/graphics/jni/Android.bp
+++ b/native/graphics/jni/Android.bp
@@ -111,6 +111,7 @@
"allocator_may_return_null = 1",
],
},
+ dictionary: "fuzz/imagedecoder_fuzzer.dict",
host_supported: true,
}
diff --git a/native/graphics/jni/fuzz/fuzz_imagedecoder.cpp b/native/graphics/jni/fuzz/fuzz_imagedecoder.cpp
index 838bf3f..6743997 100644
--- a/native/graphics/jni/fuzz/fuzz_imagedecoder.cpp
+++ b/native/graphics/jni/fuzz/fuzz_imagedecoder.cpp
@@ -15,32 +15,15 @@
*/
#include <android/imagedecoder.h>
-
#include <binder/IPCThreadState.h>
-#include <stddef.h>
-#include <stdint.h>
-#include <cstdlib>
-#include <memory>
+#include <fuzzer/FuzzedDataProvider.h>
#ifdef PNG_MUTATOR_DEFINE_LIBFUZZER_CUSTOM_MUTATOR
#include <fuzz/png_mutator.h>
#endif
-struct DecoderDeleter {
- void operator()(AImageDecoder* decoder) const { AImageDecoder_delete(decoder); }
-};
-
-using DecoderPointer = std::unique_ptr<AImageDecoder, DecoderDeleter>;
-
-static DecoderPointer makeDecoder(const uint8_t* data, size_t size) {
- AImageDecoder* decoder = nullptr;
- int result = AImageDecoder_createFromBuffer(data, size, &decoder);
- if (result != ANDROID_IMAGE_DECODER_SUCCESS) {
- // This was not a valid image.
- return nullptr;
- }
- return DecoderPointer(decoder);
-}
+constexpr int32_t kMaxDimension = 5000;
+constexpr int32_t kMinDimension = 0;
struct PixelFreer {
void operator()(void* pixels) const { std::free(pixels); }
@@ -48,41 +31,113 @@
using PixelPointer = std::unique_ptr<void, PixelFreer>;
-extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
- // Without this call, decoding HEIF may time out on binder IPC calls.
- android::ProcessState::self()->startThreadPool();
+AImageDecoder* init(const uint8_t* data, size_t size, bool useFileDescriptor) {
+ AImageDecoder* decoder = nullptr;
+ if (useFileDescriptor) {
+ constexpr char testFd[] = "tempFd";
+ int32_t fileDesc = open(testFd, O_RDWR | O_CREAT | O_TRUNC);
+ write(fileDesc, data, size);
+ AImageDecoder_createFromFd(fileDesc, &decoder);
+ close(fileDesc);
+ } else {
+ AImageDecoder_createFromBuffer(data, size, &decoder);
+ }
+ return decoder;
+}
- DecoderPointer decoder = makeDecoder(data, size);
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ FuzzedDataProvider dataProvider = FuzzedDataProvider(data, size);
+ /**
+ * Use maximum of 80% of buffer for creating decoder and save at least
+ * 20% buffer for fuzzing other APIs
+ */
+ const int32_t dataSize = dataProvider.ConsumeIntegralInRange<int32_t>(0, (size * 80) / 100);
+ std::vector<uint8_t> inputBuffer = dataProvider.ConsumeBytes<uint8_t>(dataSize);
+ AImageDecoder* decoder =
+ init(inputBuffer.data(), inputBuffer.size(), dataProvider.ConsumeBool());
if (!decoder) {
return 0;
}
-
- const AImageDecoderHeaderInfo* info = AImageDecoder_getHeaderInfo(decoder.get());
- int32_t width = AImageDecoderHeaderInfo_getWidth(info);
- int32_t height = AImageDecoderHeaderInfo_getHeight(info);
-
- // Set an arbitrary limit on the size of an image. The fuzzer runs with a
- // limited amount of memory, and keeping this allocation small allows the
- // fuzzer to continue running to try to find more serious problems. This
- // size is large enough to hold a photo taken by a current gen phone.
- constexpr int32_t kMaxDimension = 5000;
- if (width > kMaxDimension || height > kMaxDimension) {
- return 0;
+ const AImageDecoderHeaderInfo* headerInfo = AImageDecoder_getHeaderInfo(decoder);
+ AImageDecoderFrameInfo* frameInfo = AImageDecoderFrameInfo_create();
+ int32_t height = AImageDecoderHeaderInfo_getHeight(headerInfo);
+ int32_t width = AImageDecoderHeaderInfo_getWidth(headerInfo);
+ while (dataProvider.remaining_bytes()) {
+ auto invokeImageApi = dataProvider.PickValueInArray<const std::function<void()>>({
+ [&]() {
+ int32_t testHeight =
+ dataProvider.ConsumeIntegralInRange<int32_t>(kMinDimension,
+ kMaxDimension);
+ int32_t testWidth = dataProvider.ConsumeIntegralInRange<int32_t>(kMinDimension,
+ kMaxDimension);
+ int32_t result = AImageDecoder_setTargetSize(decoder, testHeight, testWidth);
+ if (result == ANDROID_IMAGE_DECODER_SUCCESS) {
+ height = testHeight;
+ width = testWidth;
+ }
+ },
+ [&]() {
+ const bool required = dataProvider.ConsumeBool();
+ AImageDecoder_setUnpremultipliedRequired(decoder, required);
+ },
+ [&]() {
+ AImageDecoder_setAndroidBitmapFormat(
+ decoder,
+ dataProvider.ConsumeIntegralInRange<
+ int32_t>(ANDROID_BITMAP_FORMAT_NONE,
+ ANDROID_BITMAP_FORMAT_RGBA_1010102) /* format */);
+ },
+ [&]() {
+ AImageDecoder_setDataSpace(decoder,
+ dataProvider
+ .ConsumeIntegral<int32_t>() /* dataspace */);
+ },
+ [&]() {
+ ARect rect{dataProvider.ConsumeIntegral<int32_t>() /* left */,
+ dataProvider.ConsumeIntegral<int32_t>() /* top */,
+ dataProvider.ConsumeIntegral<int32_t>() /* right */,
+ dataProvider.ConsumeIntegral<int32_t>() /* bottom */};
+ AImageDecoder_setCrop(decoder, rect);
+ },
+ [&]() { AImageDecoderHeaderInfo_getWidth(headerInfo); },
+ [&]() { AImageDecoderHeaderInfo_getMimeType(headerInfo); },
+ [&]() { AImageDecoderHeaderInfo_getAlphaFlags(headerInfo); },
+ [&]() { AImageDecoderHeaderInfo_getAndroidBitmapFormat(headerInfo); },
+ [&]() {
+ int32_t tempHeight;
+ int32_t tempWidth;
+ AImageDecoder_computeSampledSize(decoder,
+ dataProvider.ConsumeIntegral<
+ int>() /* sampleSize */,
+ &tempWidth, &tempHeight);
+ },
+ [&]() { AImageDecoderHeaderInfo_getDataSpace(headerInfo); },
+ [&]() { AImageDecoder_getRepeatCount(decoder); },
+ [&]() { AImageDecoder_getFrameInfo(decoder, frameInfo); },
+ [&]() { AImageDecoderFrameInfo_getDuration(frameInfo); },
+ [&]() { AImageDecoderFrameInfo_hasAlphaWithinBounds(frameInfo); },
+ [&]() { AImageDecoderFrameInfo_getDisposeOp(frameInfo); },
+ [&]() { AImageDecoderFrameInfo_getBlendOp(frameInfo); },
+ [&]() {
+ AImageDecoder_setInternallyHandleDisposePrevious(
+ decoder, dataProvider.ConsumeBool() /* handle */);
+ },
+ [&]() { AImageDecoder_rewind(decoder); },
+ [&]() { AImageDecoder_advanceFrame(decoder); },
+ [&]() {
+ size_t stride = AImageDecoder_getMinimumStride(decoder);
+ size_t pixelSize = height * stride;
+ auto pixels = PixelPointer(std::malloc(pixelSize));
+ if (!pixels.get()) {
+ return;
+ }
+ AImageDecoder_decodeImage(decoder, pixels.get(), stride, pixelSize);
+ },
+ });
+ invokeImageApi();
}
- size_t stride = AImageDecoder_getMinimumStride(decoder.get());
- size_t pixelSize = height * stride;
- auto pixels = PixelPointer(std::malloc(pixelSize));
- if (!pixels.get()) {
- return 0;
- }
-
- while (true) {
- int result = AImageDecoder_decodeImage(decoder.get(), pixels.get(), stride, pixelSize);
- if (result != ANDROID_IMAGE_DECODER_SUCCESS) break;
-
- result = AImageDecoder_advanceFrame(decoder.get());
- if (result != ANDROID_IMAGE_DECODER_SUCCESS) break;
- }
+ AImageDecoderFrameInfo_delete(frameInfo);
+ AImageDecoder_delete(decoder);
return 0;
}
diff --git a/native/graphics/jni/fuzz/imagedecoder_fuzzer.dict b/native/graphics/jni/fuzz/imagedecoder_fuzzer.dict
new file mode 100644
index 0000000..5b54a0e
--- /dev/null
+++ b/native/graphics/jni/fuzz/imagedecoder_fuzzer.dict
@@ -0,0 +1,7 @@
+kw1="\x89\x50\x4E\x47"
+kw2="\xff\xD8\xFF"
+kw4="\x52\x49\x46\x46"
+kw5="\x00\x00\x01\x00"
+kw6="\x47\x49\x46\x08"
+kw7="ftyp"
+kw8="\x04\x00\x00\x00"
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt b/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt
index 0da32bd..0b40d11 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt
@@ -71,8 +71,6 @@
import java.util.ArrayList
import java.util.Objects
import java.util.concurrent.Executors
-import org.json.JSONException
-import org.json.JSONObject
class CredentialAutofillService : AutofillService() {
@@ -81,13 +79,6 @@
private const val SESSION_ID_KEY = "autofill_session_id"
private const val REQUEST_ID_KEY = "autofill_request_id"
- private const val CRED_HINT_PREFIX = "credential="
- private const val REQUEST_DATA_KEY = "requestData"
- private const val CANDIDATE_DATA_KEY = "candidateQueryData"
- private const val SYS_PROVIDER_REQ_KEY = "isSystemProviderRequired"
- private const val CRED_OPTIONS_KEY = "credentialOptions"
- private const val TYPE_KEY = "type"
- private const val REQ_TYPE_KEY = "get"
}
override fun onFillRequest(
@@ -740,7 +731,6 @@
uniqueAutofillIdsForRequest: MutableSet<AutofillId>
) {
val traversedViewNodes: MutableSet<AutofillId> = mutableSetOf()
- val credentialOptionsFromHints: MutableMap<String, CredentialOption> = mutableMapOf()
val windowNodes: List<AssistStructure.WindowNode> =
structure.run {
(0 until windowNodeCount).map { getWindowNodeAt(it) }
@@ -749,7 +739,7 @@
windowNodes.forEach { windowNode: AssistStructure.WindowNode ->
traverseNodeForRequest(
windowNode.rootViewNode, cmRequests, responseClientState, traversedViewNodes,
- credentialOptionsFromHints, sessionId, uniqueAutofillIdsForRequest)
+ sessionId, uniqueAutofillIdsForRequest)
}
}
@@ -758,7 +748,6 @@
cmRequests: MutableList<CredentialOption>,
responseClientState: Bundle,
traversedViewNodes: MutableSet<AutofillId>,
- credentialOptionsFromHints: MutableMap<String, CredentialOption>,
sessionId: Int,
uniqueAutofillIdsForRequest: MutableSet<AutofillId>
) {
@@ -769,9 +758,8 @@
responseClientState.putBoolean(
WEBVIEW_REQUESTED_CREDENTIAL_KEY, true)
}
- cmRequests.addAll(getCredentialOptionsFromViewNode(viewNode, it, responseClientState,
- traversedViewNodes, credentialOptionsFromHints, sessionId,
- uniqueAutofillIdsForRequest)
+ cmRequests.addAll(getCredentialOptionsFromViewNode(viewNode, traversedViewNodes,
+ sessionId, uniqueAutofillIdsForRequest)
)
traversedViewNodes.add(it)
}
@@ -783,18 +771,15 @@
children.forEach { childNode: AssistStructure.ViewNode ->
traverseNodeForRequest(
- childNode, cmRequests, responseClientState, traversedViewNodes,
- credentialOptionsFromHints, sessionId, uniqueAutofillIdsForRequest
+ childNode, cmRequests, responseClientState, traversedViewNodes, sessionId,
+ uniqueAutofillIdsForRequest
)
}
}
private fun getCredentialOptionsFromViewNode(
viewNode: AssistStructure.ViewNode,
- autofillId: AutofillId,
- responseClientState: Bundle,
traversedViewNodes: MutableSet<AutofillId>,
- credentialOptionsFromHints: MutableMap<String, CredentialOption>,
sessionId: Int,
uniqueAutofillIdsForRequest: MutableSet<AutofillId>
): MutableList<CredentialOption> {
@@ -830,85 +815,6 @@
}
}
}
- // TODO(b/325502552): clean up cred option logic in autofill hint
- val credentialHints: MutableList<String> = mutableListOf()
-
- if (viewNode.autofillHints != null) {
- for (hint in viewNode.autofillHints!!) {
- if (hint.startsWith(CRED_HINT_PREFIX)) {
- credentialHints.add(hint.substringAfter(CRED_HINT_PREFIX))
- if (viewNode.webDomain != null) {
- responseClientState.putBoolean(WEBVIEW_REQUESTED_CREDENTIAL_KEY, true)
- }
- }
- }
- }
-
- for (credentialHint in credentialHints) {
- try {
- convertJsonToCredentialOption(
- credentialHint, autofillId, credentialOptionsFromHints)
- .let { credentialOptions.addAll(it) }
- } catch (e: JSONException) {
- Log.i(TAG, "Exception while parsing response: " + e.message)
- }
- }
return credentialOptions
}
-
- private fun convertJsonToCredentialOption(
- jsonString: String,
- autofillId: AutofillId,
- credentialOptionsFromHints: MutableMap<String, CredentialOption>
- ): List<CredentialOption> {
- val credentialOptions: MutableList<CredentialOption> = mutableListOf()
-
- val json = JSONObject(jsonString)
- val jsonGet = json.getJSONObject(REQ_TYPE_KEY)
- val options = jsonGet.getJSONArray(CRED_OPTIONS_KEY)
- for (i in 0 until options.length()) {
- val option = options.getJSONObject(i)
- val optionString = option.toString()
- credentialOptionsFromHints[optionString]
- ?.let { credentialOption ->
- // if the current credential option was seen before, add the current
- // viewNode to the credential option, but do not add it to the option list
- // again. This will result in the same result as deduping based on
- // traversed viewNode.
- credentialOption.candidateQueryData.getParcelableArrayList(
- CredentialProviderService.EXTRA_AUTOFILL_ID, AutofillId::class.java)
- ?.let {
- it.add(autofillId)
- credentialOption.candidateQueryData.putParcelableArrayList(
- CredentialProviderService.EXTRA_AUTOFILL_ID, it)
- }
- } ?: run {
- val candidateBundle = convertJsonToBundle(option.getJSONObject(CANDIDATE_DATA_KEY))
- candidateBundle.putParcelableArrayList(
- CredentialProviderService.EXTRA_AUTOFILL_ID,
- arrayListOf(autofillId))
- val credentialOption = CredentialOption(
- option.getString(TYPE_KEY),
- convertJsonToBundle(option.getJSONObject(REQUEST_DATA_KEY)),
- candidateBundle,
- option.getBoolean(SYS_PROVIDER_REQ_KEY),
- )
- credentialOptions.add(credentialOption)
- credentialOptionsFromHints[optionString] = credentialOption
- }
- }
- return credentialOptions
- }
-
- private fun convertJsonToBundle(json: JSONObject): Bundle {
- val result = Bundle()
- json.keys().forEach {
- val v = json.get(it)
- when (v) {
- is String -> result.putString(it, v)
- is Boolean -> result.putBoolean(it, v)
- }
- }
- return result
- }
}
\ No newline at end of file
diff --git a/packages/CtsShim/apk/arm/CtsShim.apk b/packages/CtsShim/apk/arm/CtsShim.apk
index 38a6d13..5ab190d 100644
--- a/packages/CtsShim/apk/arm/CtsShim.apk
+++ b/packages/CtsShim/apk/arm/CtsShim.apk
Binary files differ
diff --git a/packages/CtsShim/apk/arm/CtsShimPriv.apk b/packages/CtsShim/apk/arm/CtsShimPriv.apk
index bcd9836..51a8c46 100644
--- a/packages/CtsShim/apk/arm/CtsShimPriv.apk
+++ b/packages/CtsShim/apk/arm/CtsShimPriv.apk
Binary files differ
diff --git a/packages/CtsShim/apk/x86/CtsShim.apk b/packages/CtsShim/apk/x86/CtsShim.apk
index 38a6d13..5ab190d 100644
--- a/packages/CtsShim/apk/x86/CtsShim.apk
+++ b/packages/CtsShim/apk/x86/CtsShim.apk
Binary files differ
diff --git a/packages/CtsShim/apk/x86/CtsShimPriv.apk b/packages/CtsShim/apk/x86/CtsShimPriv.apk
index f778904..fcd0273 100644
--- a/packages/CtsShim/apk/x86/CtsShimPriv.apk
+++ b/packages/CtsShim/apk/x86/CtsShimPriv.apk
Binary files differ
diff --git a/packages/EasterEgg/src/com/android/egg/landroid/Physics.kt b/packages/EasterEgg/src/com/android/egg/landroid/Physics.kt
index fc66ad6..d14234e 100644
--- a/packages/EasterEgg/src/com/android/egg/landroid/Physics.kt
+++ b/packages/EasterEgg/src/com/android/egg/landroid/Physics.kt
@@ -20,7 +20,7 @@
import kotlin.random.Random
// artificially speed up or slow down the simulation
-const val TIME_SCALE = 1f
+const val TIME_SCALE = 1f // simulation seconds per wall clock second
// if it's been over 1 real second since our last timestep, don't simulate that elapsed time.
// this allows the simulation to "pause" when, for example, the activity pauses
@@ -36,6 +36,19 @@
fun postUpdate(sim: Simulator, dt: Float)
}
+interface Removable {
+ fun canBeRemoved(): Boolean
+}
+
+class Fuse(var lifetime: Float) : Removable {
+ fun update(dt: Float) {
+ lifetime -= dt
+ }
+ override fun canBeRemoved(): Boolean {
+ return lifetime < 0
+ }
+}
+
open class Body(var name: String = "Unknown") : Entity {
var pos = Vec2.Zero
var opos = Vec2.Zero
diff --git a/packages/EasterEgg/src/com/android/egg/landroid/Universe.kt b/packages/EasterEgg/src/com/android/egg/landroid/Universe.kt
index 1e54569..d6fbc11 100644
--- a/packages/EasterEgg/src/com/android/egg/landroid/Universe.kt
+++ b/packages/EasterEgg/src/com/android/egg/landroid/Universe.kt
@@ -43,11 +43,9 @@
const val MAIN_ENGINE_ACCEL = 1000f // thrust effect, pixels per second squared
const val LAUNCH_MECO = 2f // how long to suspend gravity when launching
-const val SCALED_THRUST = true
+const val LANDING_REMOVAL_TIME = 3600f // one hour of simulation time
-interface Removable {
- fun canBeRemoved(): Boolean
-}
+const val SCALED_THRUST = true
open class Planet(
val orbitCenter: Vec2,
@@ -321,7 +319,7 @@
//
(1..10).forEach {
Spark(
- lifetime = rng.nextFloatInRange(0.5f, 2f),
+ ttl = rng.nextFloatInRange(0.5f, 2f),
style = Spark.Style.DOT,
color = Color.White,
size = 1f
@@ -359,13 +357,22 @@
entities
.filterIsInstance<Removable>()
.filter(predicate = Removable::canBeRemoved)
- .filterIsInstance<Entity>()
- .forEach { remove(it) }
+ .forEach { remove(it as Entity) }
+
+ constraints
+ .filterIsInstance<Removable>()
+ .filter(predicate = Removable::canBeRemoved)
+ .forEach { remove(it as Constraint) }
}
}
-class Landing(var ship: Spacecraft?, val planet: Planet, val angle: Float, val text: String = "") :
- Constraint {
+class Landing(
+ var ship: Spacecraft?,
+ val planet: Planet,
+ val angle: Float,
+ val text: String = "",
+ private val fuse: Fuse = Fuse(LANDING_REMOVAL_TIME)
+) : Constraint, Removable by fuse {
override fun solve(sim: Simulator, dt: Float) {
ship?.let { ship ->
val landingVector = Vec2.makeWithAngleMag(angle, ship.radius + planet.radius)
@@ -373,17 +380,20 @@
ship.pos = (ship.pos * 0.5f) + (desiredPos * 0.5f) // @@@ FIXME
ship.angle = angle
}
+
+ fuse.update(dt)
}
}
class Spark(
- var lifetime: Float,
+ var ttl: Float,
collides: Boolean = false,
mass: Float = 0f,
val style: Style = Style.LINE,
val color: Color = Color.Gray,
- val size: Float = 2f
-) : Removable, Body() {
+ val size: Float = 2f,
+ val fuse: Fuse = Fuse(ttl)
+) : Removable by fuse, Body(name = "Spark") {
enum class Style {
LINE,
LINE_ABSOLUTE,
@@ -398,10 +408,7 @@
}
override fun update(sim: Simulator, dt: Float) {
super.update(sim, dt)
- lifetime -= dt
- }
- override fun canBeRemoved(): Boolean {
- return lifetime < 0
+ fuse.update(dt)
}
}
@@ -486,11 +493,11 @@
// exhaust
sim.add(
Spark(
- lifetime = sim.rng.nextFloatInRange(0.5f, 1f),
+ ttl = sim.rng.nextFloatInRange(0.5f, 1f),
collides = true,
mass = 1f,
style = Spark.Style.RING,
- size = 3f,
+ size = 1f,
color = Color(0x40FFFFFF)
)
.also { spark ->
diff --git a/packages/EasterEgg/src/com/android/egg/landroid/VisibleUniverse.kt b/packages/EasterEgg/src/com/android/egg/landroid/VisibleUniverse.kt
index 974784d..ed3ebc7 100644
--- a/packages/EasterEgg/src/com/android/egg/landroid/VisibleUniverse.kt
+++ b/packages/EasterEgg/src/com/android/egg/landroid/VisibleUniverse.kt
@@ -30,6 +30,7 @@
import androidx.core.math.MathUtils.clamp
import com.android.egg.flags.Flags.flagFlag
import java.lang.Float.max
+import kotlin.math.exp
import kotlin.math.sqrt
const val DRAW_ORBITS = true
@@ -289,7 +290,8 @@
fun ZoomedDrawScope.drawSpark(spark: Spark) {
with(spark) {
- if (lifetime < 0) return
+ if (fuse.lifetime < 0) return
+ val life = 1f - fuse.lifetime / ttl
when (style) {
Spark.Style.LINE ->
if (opos != Vec2.Zero) drawLine(color, opos, pos, strokeWidth = size)
@@ -297,7 +299,13 @@
if (opos != Vec2.Zero) drawLine(color, opos, pos, strokeWidth = size / zoom)
Spark.Style.DOT -> drawCircle(color, size, pos)
Spark.Style.DOT_ABSOLUTE -> drawCircle(color, size, pos / zoom)
- Spark.Style.RING -> drawCircle(color, size, pos, style = Stroke(width = 1f / zoom))
+ Spark.Style.RING ->
+ drawCircle(
+ color = color.copy(alpha = color.alpha * (1f - life)),
+ radius = exp(lerp(size, 3f * size, life)) - 1f,
+ center = pos,
+ style = Stroke(width = 1f / zoom)
+ )
}
}
}
diff --git a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/xerox/MDnsUtils.java b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/xerox/MDnsUtils.java
old mode 100755
new mode 100644
diff --git a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/xerox/ServiceResolver.java b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/xerox/ServiceResolver.java
old mode 100755
new mode 100644
diff --git a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/xerox/VendorInfo.java b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/xerox/VendorInfo.java
old mode 100755
new mode 100644
diff --git a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/xerox/XeroxPrintServiceRecommendationPlugin.java b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/xerox/XeroxPrintServiceRecommendationPlugin.java
old mode 100755
new mode 100644
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidDeviceManager.java
index ed964a9..b3e48b2 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidDeviceManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidDeviceManager.java
@@ -209,44 +209,34 @@
CachedBluetoothDevice mainDevice = findMainDevice(cachedDevice);
if (mainDevice != null) {
if (mainDevice.isConnected()) {
- // When main device exists and in connected state, receiving sub device
- // connection. To refresh main device UI
+ // Sub/member device is connected and main device is connected
+ // To refresh main device UI
mainDevice.refresh();
} else {
- // When both Hearing Aid devices are disconnected, receiving sub device
- // connection. To switch content and dispatch to notify UI change
- mBtManager.getEventManager().dispatchDeviceRemoved(mainDevice);
- mainDevice.switchSubDeviceContent();
- mainDevice.refresh();
- // It is necessary to do remove and add for updating the mapping on
- // preference and device
- mBtManager.getEventManager().dispatchDeviceAdded(mainDevice);
+ // Sub/member device is connected and main device is disconnected
+ // To switch content and dispatch to notify UI change
+ switchDeviceContent(mainDevice, cachedDevice);
}
return true;
}
break;
case BluetoothProfile.STATE_DISCONNECTED:
- mainDevice = findMainDevice(cachedDevice);
if (cachedDevice.getUnpairing()) {
return true;
}
+ mainDevice = findMainDevice(cachedDevice);
if (mainDevice != null) {
- // When main device exists, receiving sub device disconnection
+ // Sub/member device is disconnected and main device exists
// To update main device UI
mainDevice.refresh();
return true;
}
- CachedBluetoothDevice subDevice = cachedDevice.getSubDevice();
- if (subDevice != null && subDevice.isConnected()) {
- // Main device is disconnected and sub device is connected
- // To copy data from sub device to main device
- mBtManager.getEventManager().dispatchDeviceRemoved(cachedDevice);
- cachedDevice.switchSubDeviceContent();
- cachedDevice.refresh();
- // It is necessary to do remove and add for updating the mapping on
- // preference and device
- mBtManager.getEventManager().dispatchDeviceAdded(cachedDevice);
-
+ CachedBluetoothDevice connectedSecondaryDevice = getConnectedSecondaryDevice(
+ cachedDevice);
+ if (connectedSecondaryDevice != null) {
+ // Main device is disconnected and sub/member device is connected
+ // To switch content and dispatch to notify UI change
+ switchDeviceContent(cachedDevice, connectedSecondaryDevice);
return true;
}
break;
@@ -254,6 +244,29 @@
return false;
}
+ private void switchDeviceContent(CachedBluetoothDevice mainDevice,
+ CachedBluetoothDevice secondaryDevice) {
+ mBtManager.getEventManager().dispatchDeviceRemoved(mainDevice);
+ if (mainDevice.getSubDevice() != null
+ && mainDevice.getSubDevice().equals(secondaryDevice)) {
+ mainDevice.switchSubDeviceContent();
+ } else {
+ mainDevice.switchMemberDeviceContent(secondaryDevice);
+ }
+ mainDevice.refresh();
+ // It is necessary to do remove and add for updating the mapping on
+ // preference and device
+ mBtManager.getEventManager().dispatchDeviceAdded(mainDevice);
+ }
+
+ private CachedBluetoothDevice getConnectedSecondaryDevice(CachedBluetoothDevice cachedDevice) {
+ if (cachedDevice.getSubDevice() != null && cachedDevice.getSubDevice().isConnected()) {
+ return cachedDevice.getSubDevice();
+ }
+ return cachedDevice.getMemberDevice().stream().filter(
+ CachedBluetoothDevice::isConnected).findAny().orElse(null);
+ }
+
void onActiveDeviceChanged(CachedBluetoothDevice device) {
if (FeatureFlagUtils.isEnabled(mContext, FeatureFlagUtils.SETTINGS_AUDIO_ROUTING)) {
if (device.isActiveDevice(BluetoothProfile.HEARING_AID) || device.isActiveDevice(
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/DeviceIconUtil.java b/packages/SettingsLib/src/com/android/settingslib/media/DeviceIconUtil.java
index 3de4933..717a8ee 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/DeviceIconUtil.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/DeviceIconUtil.java
@@ -16,135 +16,136 @@
package com.android.settingslib.media;
+import static android.media.AudioDeviceInfo.AudioDeviceType;
+import static android.media.AudioDeviceInfo.TYPE_BUILTIN_SPEAKER;
+import static android.media.AudioDeviceInfo.TYPE_DOCK;
+import static android.media.AudioDeviceInfo.TYPE_HDMI;
+import static android.media.AudioDeviceInfo.TYPE_HDMI_ARC;
+import static android.media.AudioDeviceInfo.TYPE_HDMI_EARC;
+import static android.media.AudioDeviceInfo.TYPE_USB_ACCESSORY;
+import static android.media.AudioDeviceInfo.TYPE_USB_DEVICE;
+import static android.media.AudioDeviceInfo.TYPE_USB_HEADSET;
+import static android.media.AudioDeviceInfo.TYPE_WIRED_HEADPHONES;
+import static android.media.AudioDeviceInfo.TYPE_WIRED_HEADSET;
+
import android.annotation.DrawableRes;
+import android.annotation.SuppressLint;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
-import android.media.AudioDeviceInfo;
import android.media.MediaRoute2Info;
+import android.os.SystemProperties;
+import android.util.SparseIntArray;
+import androidx.annotation.NonNull;
+
+import com.android.internal.annotations.VisibleForTesting;
import com.android.settingslib.R;
import com.android.settingslib.media.flags.Flags;
import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.util.Objects;
/** A util class to get the appropriate icon for different device types. */
public class DeviceIconUtil {
- // A default icon to use if the type is not present in the map.
- @DrawableRes private static final int DEFAULT_ICON = R.drawable.ic_smartphone;
- @DrawableRes private static final int DEFAULT_ICON_TV = R.drawable.ic_media_speaker_device;
-
- // A map from a @AudioDeviceInfo.AudioDeviceType to full device information.
- private final Map<Integer, Device> mAudioDeviceTypeToIconMap = new HashMap<>();
- // A map from a @MediaRoute2Info.Type to full device information.
- private final Map<Integer, Device> mMediaRouteTypeToIconMap = new HashMap<>();
+ private static final SparseIntArray AUDIO_DEVICE_TO_MEDIA_ROUTE_TYPE = new SparseIntArray();
private final boolean mIsTv;
-
- public DeviceIconUtil(Context context) {
- this(context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK));
+ private final boolean mIsTablet;
+ private final Context mContext;
+ public DeviceIconUtil(@NonNull Context context) {
+ mContext = Objects.requireNonNull(context);
+ mIsTv =
+ mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK)
+ && Flags.enableTvMediaOutputDialog();
+ mIsTablet =
+ Arrays.asList(SystemProperties.get("ro.build.characteristics").split(","))
+ .contains("tablet");
}
- public DeviceIconUtil(boolean isTv) {
- mIsTv = isTv && Flags.enableTvMediaOutputDialog();
- List<Device> deviceList = Arrays.asList(
- new Device(
- AudioDeviceInfo.TYPE_USB_DEVICE,
- MediaRoute2Info.TYPE_USB_DEVICE,
- R.drawable.ic_headphone),
- new Device(
- AudioDeviceInfo.TYPE_USB_HEADSET,
- MediaRoute2Info.TYPE_USB_HEADSET,
- R.drawable.ic_headphone),
- new Device(
- AudioDeviceInfo.TYPE_USB_ACCESSORY,
- MediaRoute2Info.TYPE_USB_ACCESSORY,
- mIsTv ? R.drawable.ic_usb : R.drawable.ic_headphone),
- new Device(
- AudioDeviceInfo.TYPE_DOCK,
- MediaRoute2Info.TYPE_DOCK,
- R.drawable.ic_dock_device),
- new Device(
- AudioDeviceInfo.TYPE_HDMI,
- MediaRoute2Info.TYPE_HDMI,
- mIsTv ? R.drawable.ic_tv : R.drawable.ic_external_display),
- new Device(
- AudioDeviceInfo.TYPE_HDMI_ARC,
- MediaRoute2Info.TYPE_HDMI_ARC,
- mIsTv ? R.drawable.ic_hdmi : R.drawable.ic_external_display),
- new Device(
- AudioDeviceInfo.TYPE_HDMI_EARC,
- MediaRoute2Info.TYPE_HDMI_EARC,
- mIsTv ? R.drawable.ic_hdmi : R.drawable.ic_external_display),
- new Device(
- AudioDeviceInfo.TYPE_WIRED_HEADSET,
- MediaRoute2Info.TYPE_WIRED_HEADSET,
- mIsTv ? R.drawable.ic_wired_device : R.drawable.ic_headphone),
- new Device(
- AudioDeviceInfo.TYPE_WIRED_HEADPHONES,
- MediaRoute2Info.TYPE_WIRED_HEADPHONES,
- mIsTv ? R.drawable.ic_wired_device : R.drawable.ic_headphone),
- new Device(
- AudioDeviceInfo.TYPE_BUILTIN_SPEAKER,
- MediaRoute2Info.TYPE_BUILTIN_SPEAKER,
- mIsTv ? R.drawable.ic_tv : R.drawable.ic_smartphone));
- for (int i = 0; i < deviceList.size(); i++) {
- Device device = deviceList.get(i);
- mAudioDeviceTypeToIconMap.put(device.mAudioDeviceType, device);
- mMediaRouteTypeToIconMap.put(device.mMediaRouteType, device);
- }
- }
-
- private int getDefaultIcon() {
- return mIsTv ? DEFAULT_ICON_TV : DEFAULT_ICON;
+ @VisibleForTesting
+ /* package */ DeviceIconUtil(boolean isTv) {
+ mContext = null;
+ mIsTv = isTv;
+ mIsTablet = false;
}
/** Returns a drawable for an icon representing the given audioDeviceType. */
- public Drawable getIconFromAudioDeviceType(
- @AudioDeviceInfo.AudioDeviceType int audioDeviceType, Context context) {
- return context.getDrawable(getIconResIdFromAudioDeviceType(audioDeviceType));
+ public Drawable getIconFromAudioDeviceType(@AudioDeviceType int audioDeviceType) {
+ return mContext.getDrawable(getIconResIdFromAudioDeviceType(audioDeviceType));
}
/** Returns a drawable res ID for an icon representing the given audioDeviceType. */
@DrawableRes
- public int getIconResIdFromAudioDeviceType(
- @AudioDeviceInfo.AudioDeviceType int audioDeviceType) {
- if (mAudioDeviceTypeToIconMap.containsKey(audioDeviceType)) {
- return mAudioDeviceTypeToIconMap.get(audioDeviceType).mIconDrawableRes;
- }
- return getDefaultIcon();
+ public int getIconResIdFromAudioDeviceType(@AudioDeviceType int audioDeviceType) {
+ int mediaRouteType =
+ AUDIO_DEVICE_TO_MEDIA_ROUTE_TYPE.get(audioDeviceType, /* defaultValue */ -1);
+ return getIconResIdFromMediaRouteType(mediaRouteType);
}
/** Returns a drawable res ID for an icon representing the given mediaRouteType. */
@DrawableRes
- public int getIconResIdFromMediaRouteType(
- @MediaRoute2Info.Type int mediaRouteType) {
- if (mMediaRouteTypeToIconMap.containsKey(mediaRouteType)) {
- return mMediaRouteTypeToIconMap.get(mediaRouteType).mIconDrawableRes;
- }
- return getDefaultIcon();
+ public int getIconResIdFromMediaRouteType(@MediaRoute2Info.Type int type) {
+ return mIsTv
+ ? getIconResourceIdForTv(type)
+ : getIconResourceIdForPhoneOrTablet(type, mIsTablet);
}
- private static class Device {
- @AudioDeviceInfo.AudioDeviceType
- private final int mAudioDeviceType;
+ @SuppressLint("SwitchIntDef")
+ @DrawableRes
+ private static int getIconResourceIdForPhoneOrTablet(
+ @MediaRoute2Info.Type int type, boolean isTablet) {
+ int defaultResId = isTablet ? R.drawable.ic_media_tablet : R.drawable.ic_smartphone;
- @MediaRoute2Info.Type
- private final int mMediaRouteType;
+ return switch (type) {
+ case MediaRoute2Info.TYPE_USB_DEVICE,
+ MediaRoute2Info.TYPE_USB_HEADSET,
+ MediaRoute2Info.TYPE_USB_ACCESSORY,
+ MediaRoute2Info.TYPE_WIRED_HEADSET,
+ MediaRoute2Info.TYPE_WIRED_HEADPHONES ->
+ R.drawable.ic_headphone;
+ case MediaRoute2Info.TYPE_DOCK -> R.drawable.ic_dock_device;
+ case MediaRoute2Info.TYPE_HDMI,
+ MediaRoute2Info.TYPE_HDMI_ARC,
+ MediaRoute2Info.TYPE_HDMI_EARC ->
+ R.drawable.ic_external_display;
+ default -> defaultResId; // Includes TYPE_BUILTIN_SPEAKER.
+ };
+ }
- @DrawableRes
- private final int mIconDrawableRes;
+ @SuppressLint("SwitchIntDef")
+ @DrawableRes
+ private static int getIconResourceIdForTv(@MediaRoute2Info.Type int type) {
+ return switch (type) {
+ case MediaRoute2Info.TYPE_USB_DEVICE, MediaRoute2Info.TYPE_USB_HEADSET ->
+ R.drawable.ic_headphone;
+ case MediaRoute2Info.TYPE_USB_ACCESSORY -> R.drawable.ic_usb;
+ case MediaRoute2Info.TYPE_DOCK -> R.drawable.ic_dock_device;
+ case MediaRoute2Info.TYPE_HDMI, MediaRoute2Info.TYPE_BUILTIN_SPEAKER ->
+ R.drawable.ic_tv;
+ case MediaRoute2Info.TYPE_HDMI_ARC, MediaRoute2Info.TYPE_HDMI_EARC ->
+ R.drawable.ic_hdmi;
+ case MediaRoute2Info.TYPE_WIRED_HEADSET, MediaRoute2Info.TYPE_WIRED_HEADPHONES ->
+ R.drawable.ic_wired_device;
+ default -> R.drawable.ic_media_speaker_device;
+ };
+ }
- Device(@AudioDeviceInfo.AudioDeviceType int audioDeviceType,
- @MediaRoute2Info.Type int mediaRouteType,
- @DrawableRes int iconDrawableRes) {
- mAudioDeviceType = audioDeviceType;
- mMediaRouteType = mediaRouteType;
- mIconDrawableRes = iconDrawableRes;
- }
+ static {
+ AUDIO_DEVICE_TO_MEDIA_ROUTE_TYPE.put(TYPE_USB_DEVICE, MediaRoute2Info.TYPE_USB_DEVICE);
+ AUDIO_DEVICE_TO_MEDIA_ROUTE_TYPE.put(TYPE_USB_HEADSET, MediaRoute2Info.TYPE_USB_HEADSET);
+ AUDIO_DEVICE_TO_MEDIA_ROUTE_TYPE.put(
+ TYPE_USB_ACCESSORY, MediaRoute2Info.TYPE_USB_ACCESSORY);
+ AUDIO_DEVICE_TO_MEDIA_ROUTE_TYPE.put(TYPE_DOCK, MediaRoute2Info.TYPE_DOCK);
+ AUDIO_DEVICE_TO_MEDIA_ROUTE_TYPE.put(TYPE_HDMI, MediaRoute2Info.TYPE_HDMI);
+ AUDIO_DEVICE_TO_MEDIA_ROUTE_TYPE.put(TYPE_HDMI_ARC, MediaRoute2Info.TYPE_HDMI_ARC);
+ AUDIO_DEVICE_TO_MEDIA_ROUTE_TYPE.put(TYPE_HDMI_EARC, MediaRoute2Info.TYPE_HDMI_EARC);
+ AUDIO_DEVICE_TO_MEDIA_ROUTE_TYPE.put(
+ TYPE_WIRED_HEADSET, MediaRoute2Info.TYPE_WIRED_HEADSET);
+ AUDIO_DEVICE_TO_MEDIA_ROUTE_TYPE.put(
+ TYPE_WIRED_HEADPHONES, MediaRoute2Info.TYPE_WIRED_HEADPHONES);
+ AUDIO_DEVICE_TO_MEDIA_ROUTE_TYPE.put(
+ TYPE_BUILTIN_SPEAKER, MediaRoute2Info.TYPE_BUILTIN_SPEAKER);
}
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidDeviceManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidDeviceManagerTest.java
index 4188d2e..bf927a1 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidDeviceManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidDeviceManagerTest.java
@@ -681,6 +681,53 @@
verify(mCachedDevice1).refresh();
}
+
+ /**
+ * Test onProfileConnectionStateChangedIfProcessed.
+ * When main device is disconnected, to verify switch() result for member device connected
+ * event
+ */
+ @Test
+ public void onProfileConnectionStateChanged_connect_member_mainDisconnected_switch() {
+ when(mCachedDevice1.isConnected()).thenReturn(false);
+ when(mCachedDevice1.getGroupId()).thenReturn(GROUP_ID_1);
+ when(mCachedDevice2.getGroupId()).thenReturn(GROUP_ID_1);
+ mCachedDeviceManager.mCachedDevices.add(mCachedDevice1);
+ mCachedDevice1.addMemberDevice(mCachedDevice2);
+
+ assertThat(mCachedDevice1.mDevice).isEqualTo(mDevice1);
+ assertThat(mCachedDevice2.mDevice).isEqualTo(mDevice2);
+ assertThat(mHearingAidDeviceManager.onProfileConnectionStateChangedIfProcessed(
+ mCachedDevice2, BluetoothProfile.STATE_CONNECTED)).isTrue();
+
+ assertThat(mCachedDevice1.mDevice).isEqualTo(mDevice2);
+ assertThat(mCachedDevice2.mDevice).isEqualTo(mDevice1);
+ verify(mCachedDevice1).refresh();
+ }
+
+ /**
+ * Test onProfileConnectionStateChangedIfProcessed.
+ * When member device is connected, to verify switch() result for main device disconnected
+ * event
+ */
+ @Test
+ public void onProfileConnectionStateChanged_disconnect_main_subDeviceConnected_switch() {
+ when(mCachedDevice2.isConnected()).thenReturn(true);
+ when(mCachedDevice1.getGroupId()).thenReturn(GROUP_ID_1);
+ when(mCachedDevice2.getGroupId()).thenReturn(GROUP_ID_1);
+ mCachedDeviceManager.mCachedDevices.add(mCachedDevice1);
+ mCachedDevice1.addMemberDevice(mCachedDevice2);
+
+ assertThat(mCachedDevice1.mDevice).isEqualTo(mDevice1);
+ assertThat(mCachedDevice2.mDevice).isEqualTo(mDevice2);
+ assertThat(mHearingAidDeviceManager.onProfileConnectionStateChangedIfProcessed(
+ mCachedDevice1, BluetoothProfile.STATE_DISCONNECTED)).isTrue();
+
+ assertThat(mCachedDevice1.mDevice).isEqualTo(mDevice2);
+ assertThat(mCachedDevice2.mDevice).isEqualTo(mDevice1);
+ verify(mCachedDevice1).refresh();
+ }
+
@Test
public void onActiveDeviceChanged_connected_callSetStrategies() {
when(mHelper.getMatchedHearingDeviceAttributes(mCachedDevice1)).thenReturn(
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/DeviceIconUtilTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/DeviceIconUtilTest.java
index 8edda1a..883640d 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/DeviceIconUtilTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/DeviceIconUtilTest.java
@@ -18,6 +18,7 @@
import static com.google.common.truth.Truth.assertThat;
+import android.content.Context;
import android.media.AudioDeviceInfo;
import android.media.MediaRoute2Info;
import android.platform.test.flag.junit.SetFlagsRule;
@@ -30,6 +31,8 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.shadows.ShadowSystemProperties;
@RunWith(RobolectricTestRunner.class)
public class DeviceIconUtilTest {
@@ -37,9 +40,12 @@
@Rule
public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+ private Context mContext;
+
@Before
public void setup() {
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_TV_MEDIA_OUTPUT_DIALOG);
+ mContext = RuntimeEnvironment.getApplication();
}
@Test
@@ -171,6 +177,14 @@
}
@Test
+ public void getIconResIdFromMediaRouteType_onTablet_builtinSpeaker_isTablet() {
+ ShadowSystemProperties.override("ro.build.characteristics", "tablet");
+ assertThat(new DeviceIconUtil(mContext)
+ .getIconResIdFromMediaRouteType(MediaRoute2Info.TYPE_BUILTIN_SPEAKER))
+ .isEqualTo(R.drawable.ic_media_tablet);
+ }
+
+ @Test
public void getIconResIdFromMediaRouteType_unsupportedType_isSmartphone() {
assertThat(new DeviceIconUtil(/* isTv */ false)
.getIconResIdFromMediaRouteType(MediaRoute2Info.TYPE_UNKNOWN))
@@ -178,6 +192,14 @@
}
@Test
+ public void getIconResIdFromMediaRouteType_onTablet_unsupportedType_isTablet() {
+ ShadowSystemProperties.override("ro.build.characteristics", "tablet");
+ assertThat(new DeviceIconUtil(mContext)
+ .getIconResIdFromMediaRouteType(MediaRoute2Info.TYPE_UNKNOWN))
+ .isEqualTo(R.drawable.ic_media_tablet);
+ }
+
+ @Test
public void getIconResIdFromMediaRouteType_tv_unsupportedType_isSpeaker() {
assertThat(new DeviceIconUtil(/* isTv */ true)
.getIconResIdFromMediaRouteType(MediaRoute2Info.TYPE_UNKNOWN))
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index c2c334b..58c39b4 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -78,10 +78,50 @@
visibility: ["//visibility:private"],
}
+// Tests where robolectric conversion caused errors in SystemUITests at runtime
+filegroup {
+ name: "SystemUI-tests-broken-robofiles-sysui-run",
+ srcs: [
+ "tests/src/**/systemui/broadcast/BroadcastDispatcherTest.kt",
+ "tests/src/**/systemui/broadcast/ActionReceiverTest.kt",
+ "tests/src/**/systemui/doze/DozeMachineTest.java",
+ "tests/src/**/systemui/globalactions/GlobalActionsDialogLiteTest.java",
+ "tests/src/**/systemui/globalactions/GlobalActionsImeTest.java",
+ "tests/src/**/systemui/keyguard/data/repository/KeyguardTransitionRepositoryTest.kt",
+ "tests/src/**/systemui/media/controls/domain/pipeline/LegacyMediaDataManagerImplTest.kt",
+ "tests/src/**/systemui/media/controls/domain/pipeline/MediaDataProcessorTest.kt",
+ "tests/src/**/systemui/media/dialog/MediaOutputAdapterTest.java",
+ "tests/src/**/systemui/media/dialog/MediaOutputBaseDialogTest.java",
+ "tests/src/**/systemui/media/dialog/MediaOutputBroadcastDialogTest.java",
+ "tests/src/**/systemui/media/dialog/MediaOutputDialogTest.java",
+ "tests/src/**/systemui/mediaprojection/permission/MediaProjectionPermissionDialogDelegateTest.kt",
+ ],
+}
+
// Tests where robolectric failed at runtime. (go/multivalent-tests)
filegroup {
name: "SystemUI-tests-broken-robofiles-run",
srcs: [
+ "tests/src/**/systemui/accessibility/AccessibilityButtonModeObserverTest.java",
+ "tests/src/**/systemui/accessibility/AccessibilityButtonTargetsObserverTest.java",
+ "tests/src/**/systemui/accessibility/FullscreenMagnificationControllerTest.java",
+ "tests/src/**/systemui/accessibility/WindowMagnificationAnimationControllerTest.java",
+ "tests/src/**/systemui/animation/FontInterpolatorTest.kt",
+ "tests/src/**/systemui/animation/TextAnimatorTest.kt",
+ "tests/src/**/systemui/animation/TextInterpolatorTest.kt",
+ "tests/src/**/systemui/animation/ActivityTransitionAnimatorTest.kt",
+ "tests/src/**/systemui/animation/AnimatorTestRuleOrderTest.kt",
+ "tests/src/**/systemui/animation/DialogTransitionAnimatorTest.kt",
+ "tests/src/**/systemui/broadcast/ActionReceiverTest.kt",
+ "tests/src/**/systemui/broadcast/BroadcastDispatcherTest.kt",
+ "tests/src/**/systemui/compose/ComposeInitializerTest.kt",
+ "tests/src/**/systemui/controls/ui/ControlsActivityTest.kt",
+ "tests/src/**/systemui/controls/management/ControlsEditingActivityTest.kt",
+ "tests/src/**/systemui/controls/management/ControlsRequestDialogTest.kt",
+ "tests/src/**/systemui/controls/ui/DetailDialogTest.kt",
+ "tests/src/**/systemui/doze/DozeMachineTest.kt",
+ "tests/src/**/systemui/fontscaling/FontScalingDialogDelegateTest.kt",
+ "tests/src/**/systemui/keyguard/CustomizationProviderTest.kt",
"tests/src/**/systemui/globalactions/GlobalActionsColumnLayoutTest.java",
"tests/src/**/systemui/globalactions/GlobalActionsDialogLiteTest.java",
"tests/src/**/systemui/globalactions/GlobalActionsImeTest.java",
@@ -176,9 +216,7 @@
],
}
-// We are running robolectric tests in the tests directory as well as
-// multivalent tests. If you add a test, and it doesn't run in robolectric,
-// it should be added to this exclusion list. go/multivalent-tests
+// Tests where robolectric failed at compile time. (go/multivalent-tests)
filegroup {
name: "SystemUI-tests-broken-robofiles-compile",
srcs: [
@@ -330,6 +368,7 @@
"tests/src/**/systemui/shared/system/RemoteTransitionTest.java",
"tests/src/**/systemui/navigationbar/NavigationBarControllerImplTest.java",
"tests/src/**/systemui/bluetooth/qsdialog/AudioSharingInteractorTest.kt",
+ "tests/src/**/systemui/bluetooth/qsdialog/DeviceItemActionInteractorTest.kt",
"tests/src/**/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfigTest.kt",
"tests/src/**/systemui/notetask/LaunchNotesRoleSettingsTrampolineActivityTest.kt",
"tests/src/**/systemui/notetask/shortcut/LaunchNoteTaskActivityTest.kt",
@@ -746,7 +785,6 @@
kotlincflags: ["-Xjvm-default=all"],
optimize: {
shrink_resources: false,
- optimized_shrink_resources: false,
proguard_flags_files: ["proguard.flags"],
},
@@ -811,6 +849,7 @@
exclude_srcs: [
":SystemUI-tests-broken-robofiles-compile",
":SystemUI-tests-broken-robofiles-run",
+ ":SystemUI-tests-broken-robofiles-sysui-run",
],
static_libs: [
"RoboTestLibraries",
@@ -882,7 +921,6 @@
optimize: true,
shrink: true,
shrink_resources: true,
- optimized_shrink_resources: true,
ignore_warnings: false,
proguard_compatibility: false,
},
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index a9c4399..bd6efe5 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -650,6 +650,7 @@
<!-- started from MediaProjectionManager -->
<activity
android:name=".mediaprojection.permission.MediaProjectionPermissionActivity"
+ android:showForAllUsers="true"
android:exported="true"
android:theme="@style/Theme.SystemUI.MediaProjectionAlertDialog"
android:finishOnCloseSystemDialogs="true"
@@ -660,6 +661,7 @@
<activity
android:name=".mediaprojection.appselector.MediaProjectionAppSelectorActivity"
android:theme="@style/Theme.SystemUI.MediaProjectionAppSelector"
+ android:showForAllUsers="true"
android:finishOnCloseSystemDialogs="true"
android:excludeFromRecents="true"
android:documentLaunchMode="never"
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index 4311e79..85aa33a 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -981,6 +981,16 @@
}
flag {
+ name: "media_controls_lockscreen_shade_bug_fix"
+ namespace: "systemui"
+ description: "Use ShadeInteractor for media location changes"
+ bug: "319244625"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
namespace: "systemui"
name: "enable_view_capture_tracing"
description: "Enables view capture tracing in System UI."
@@ -1039,6 +1049,16 @@
}
flag {
+ name: "glanceable_hub_animate_timer_activity_starts"
+ namespace: "systemui"
+ description: "Properly animates activity starts from live timers on the glanceable hub"
+ bug: "345741071"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
name: "new_touchpad_gestures_tutorial"
namespace: "systemui"
description: "Enables new interactive tutorial for learning touchpad gestures"
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContent.kt
index 77665155..60b6f62 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContent.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContent.kt
@@ -24,6 +24,7 @@
import com.android.compose.animation.scene.SceneScope
import com.android.compose.theme.LocalAndroidColorScheme
import com.android.systemui.communal.ui.viewmodel.CommunalViewModel
+import com.android.systemui.communal.widgets.WidgetInteractionHandler
import com.android.systemui.keyguard.ui.composable.blueprint.BlueprintAlignmentLines
import com.android.systemui.keyguard.ui.composable.section.LockSection
import com.android.systemui.statusbar.phone.SystemUIDialogFactory
@@ -34,6 +35,7 @@
@Inject
constructor(
private val viewModel: CommunalViewModel,
+ private val interactionHandler: WidgetInteractionHandler,
private val dialogFactory: SystemUIDialogFactory,
private val lockSection: LockSection,
) {
@@ -45,6 +47,7 @@
content = {
CommunalHub(
viewModel = viewModel,
+ interactionHandler = interactionHandler,
dialogFactory = dialogFactory,
modifier = Modifier.element(Communal.Elements.Grid)
)
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
index 1f7f07b..eccb072 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
@@ -16,13 +16,13 @@
package com.android.systemui.communal.ui.compose
-import android.appwidget.AppWidgetHostView
import android.graphics.drawable.Icon
import android.os.Bundle
import android.util.SizeF
import android.view.View.IMPORTANT_FOR_ACCESSIBILITY_AUTO
import android.view.View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
import android.widget.FrameLayout
+import android.widget.RemoteViews
import androidx.annotation.VisibleForTesting
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.AnimatedVisibilityScope
@@ -132,6 +132,7 @@
import com.android.compose.theme.LocalAndroidColorScheme
import com.android.compose.ui.graphics.painter.rememberDrawablePainter
import com.android.internal.R.dimen.system_app_widget_background_radius
+import com.android.systemui.Flags.glanceableHubAnimateTimerActivityStarts
import com.android.systemui.communal.domain.model.CommunalContentModel
import com.android.systemui.communal.shared.model.CommunalContentSize
import com.android.systemui.communal.shared.model.CommunalScenes
@@ -144,6 +145,7 @@
import com.android.systemui.communal.ui.viewmodel.CommunalEditModeViewModel
import com.android.systemui.communal.ui.viewmodel.CommunalViewModel
import com.android.systemui.communal.ui.viewmodel.PopupType
+import com.android.systemui.communal.widgets.SmartspaceAppWidgetHostView
import com.android.systemui.communal.widgets.WidgetConfigurator
import com.android.systemui.res.R
import com.android.systemui.statusbar.phone.SystemUIDialogFactory
@@ -154,6 +156,7 @@
fun CommunalHub(
modifier: Modifier = Modifier,
viewModel: BaseCommunalViewModel,
+ interactionHandler: RemoteViews.InteractionHandler? = null,
dialogFactory: SystemUIDialogFactory? = null,
widgetConfigurator: WidgetConfigurator? = null,
onOpenWidgetPicker: (() -> Unit)? = null,
@@ -262,6 +265,7 @@
contentListState = contentListState,
selectedKey = selectedKey,
widgetConfigurator = widgetConfigurator,
+ interactionHandler = interactionHandler,
)
}
}
@@ -391,6 +395,7 @@
setGridCoordinates: (coordinates: LayoutCoordinates) -> Unit,
updateDragPositionForRemove: (offset: Offset) -> Boolean,
widgetConfigurator: WidgetConfigurator?,
+ interactionHandler: RemoteViews.InteractionHandler?,
) {
var gridModifier =
Modifier.align(Alignment.TopStart).onGloballyPositioned { setGridCoordinates(it) }
@@ -468,7 +473,8 @@
selected = selected && !isDragging,
widgetConfigurator = widgetConfigurator,
index = index,
- contentListState = contentListState
+ contentListState = contentListState,
+ interactionHandler = interactionHandler,
)
}
} else {
@@ -479,7 +485,8 @@
size = size,
selected = false,
index = index,
- contentListState = contentListState
+ contentListState = contentListState,
+ interactionHandler = interactionHandler,
)
}
}
@@ -759,6 +766,7 @@
widgetConfigurator: WidgetConfigurator? = null,
index: Int,
contentListState: ContentListState,
+ interactionHandler: RemoteViews.InteractionHandler?,
) {
when (model) {
is CommunalContentModel.WidgetContent.Widget ->
@@ -778,7 +786,7 @@
is CommunalContentModel.WidgetContent.PendingWidget ->
PendingWidgetPlaceholder(model, modifier)
is CommunalContentModel.CtaTileInViewMode -> CtaTileInViewModeContent(viewModel, modifier)
- is CommunalContentModel.Smartspace -> SmartspaceContent(model, modifier)
+ is CommunalContentModel.Smartspace -> SmartspaceContent(interactionHandler, model, modifier)
is CommunalContentModel.Tutorial -> TutorialContent(modifier)
is CommunalContentModel.Umo -> Umo(viewModel, modifier)
}
@@ -1091,13 +1099,19 @@
@Composable
private fun SmartspaceContent(
+ interactionHandler: RemoteViews.InteractionHandler?,
model: CommunalContentModel.Smartspace,
modifier: Modifier = Modifier,
) {
AndroidView(
modifier = modifier,
factory = { context ->
- AppWidgetHostView(context).apply { updateAppWidget(model.remoteViews) }
+ SmartspaceAppWidgetHostView(context).apply {
+ if (glanceableHubAnimateTimerActivityStarts()) {
+ interactionHandler?.let { setInteractionHandler(it) }
+ }
+ updateAppWidget(model.remoteViews)
+ }
},
// For reusing composition in lazy lists.
onReset = {},
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalScene.kt
index 9e905ac..94018bb 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalScene.kt
@@ -24,6 +24,7 @@
import com.android.compose.animation.scene.UserAction
import com.android.compose.animation.scene.UserActionResult
import com.android.systemui.communal.ui.viewmodel.CommunalViewModel
+import com.android.systemui.communal.widgets.WidgetInteractionHandler
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.scene.ui.composable.ComposableScene
@@ -40,6 +41,7 @@
constructor(
private val viewModel: CommunalViewModel,
private val dialogFactory: SystemUIDialogFactory,
+ private val interactionHandler: WidgetInteractionHandler,
) : ComposableScene {
override val key = Scenes.Communal
@@ -53,6 +55,6 @@
@Composable
override fun SceneScope.Content(modifier: Modifier) {
- CommunalHub(modifier, viewModel, dialogFactory)
+ CommunalHub(modifier, viewModel, interactionHandler, dialogFactory)
}
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/spatialaudio/ui/composable/SpatialAudioPopup.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/spatialaudio/ui/composable/SpatialAudioPopup.kt
index 9891b5b..3295dde 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/spatialaudio/ui/composable/SpatialAudioPopup.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/spatialaudio/ui/composable/SpatialAudioPopup.kt
@@ -17,6 +17,7 @@
package com.android.systemui.volume.panel.component.spatialaudio.ui.composable
import android.view.Gravity
+import androidx.annotation.VisibleForTesting
import androidx.compose.foundation.basicMarquee
import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.MaterialTheme
@@ -71,7 +72,8 @@
}
@Composable
- private fun Content(dialog: SystemUIDialog) {
+ @VisibleForTesting
+ fun Content(dialog: SystemUIDialog) {
val isAvailable by viewModel.isAvailable.collectAsStateWithLifecycle()
if (!isAvailable) {
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateSharedAsState.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateSharedAsState.kt
index 7fd3a176..114dcf4 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateSharedAsState.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateSharedAsState.kt
@@ -381,18 +381,17 @@
// relayout/redraw for nothing.
fromValue
} else {
- // In the case of bouncing, if the value remains constant during the overscroll, we
- // should use the value of the scene we are bouncing around.
- if (!canOverflow && transition is TransitionState.HasOverscrollProperties) {
- val bouncingScene = transition.bouncingScene
- if (bouncingScene != null) {
- return sharedValue[bouncingScene]
- }
- }
-
+ val overscrollSpec = transition.currentOverscrollSpec
val progress =
- if (canOverflow) transition.progress
- else transition.progress.fastCoerceIn(0f, 1f)
+ when {
+ overscrollSpec == null -> {
+ if (canOverflow) transition.progress
+ else transition.progress.fastCoerceIn(0f, 1f)
+ }
+ overscrollSpec.scene == transition.toScene -> 1f
+ else -> 0f
+ }
+
sharedValue.type.lerp(fromValue, toValue, progress)
}
} else fromValue ?: toValue
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MultiPointerDraggable.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MultiPointerDraggable.kt
index 3cc8431..6001f1f 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MultiPointerDraggable.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MultiPointerDraggable.kt
@@ -19,8 +19,6 @@
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.foundation.gestures.awaitHorizontalTouchSlopOrCancellation
import androidx.compose.foundation.gestures.awaitVerticalTouchSlopOrCancellation
-import androidx.compose.foundation.gestures.horizontalDrag
-import androidx.compose.foundation.gestures.verticalDrag
import androidx.compose.runtime.Stable
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
@@ -32,7 +30,9 @@
import androidx.compose.ui.input.pointer.PointerInputScope
import androidx.compose.ui.input.pointer.SuspendingPointerInputModifierNode
import androidx.compose.ui.input.pointer.changedToDownIgnoreConsumed
+import androidx.compose.ui.input.pointer.changedToUpIgnoreConsumed
import androidx.compose.ui.input.pointer.positionChange
+import androidx.compose.ui.input.pointer.positionChangeIgnoreConsumed
import androidx.compose.ui.input.pointer.util.VelocityTracker
import androidx.compose.ui.input.pointer.util.addPointerInputChange
import androidx.compose.ui.node.CompositionLocalConsumerModifierNode
@@ -46,6 +46,8 @@
import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.unit.Velocity
import androidx.compose.ui.util.fastAll
+import androidx.compose.ui.util.fastAny
+import androidx.compose.ui.util.fastFirstOrNull
import androidx.compose.ui.util.fastForEach
import kotlin.coroutines.cancellation.CancellationException
import kotlin.math.sign
@@ -236,8 +238,23 @@
onDragCancel: (controller: DragController) -> Unit,
swipeDetector: SwipeDetector,
) {
- // Wait for a consumable event in [PointerEventPass.Main] pass
- val consumablePointer = awaitConsumableEvent().changes.first()
+ val consumablePointer =
+ awaitConsumableEvent {
+ // We are searching for an event that can be used as the starting point for the
+ // drag gesture. Our options are:
+ // - Initial: These events should never be consumed by the MultiPointerDraggable
+ // since our ancestors can consume the gesture, but we would eliminate this
+ // possibility for our descendants.
+ // - Main: These events are consumed during the drag gesture, and they are a
+ // good place to start if the previous event has not been consumed.
+ // - Final: If the previous event has been consumed, we can wait for the Main
+ // pass to finish. If none of our ancestors were interested in the event, we
+ // can wait for an unconsumed event in the Final pass.
+ val previousConsumed = currentEvent.changes.fastAny { it.isConsumed }
+ if (previousConsumed) PointerEventPass.Final else PointerEventPass.Main
+ }
+ .changes
+ .first()
var overSlop = 0f
val drag =
@@ -297,18 +314,22 @@
onDrag(controller, drag, overSlop)
successful =
- when (orientation) {
- Orientation.Horizontal ->
- horizontalDrag(drag.id) {
- onDrag(controller, it, it.positionChange().toFloat())
- it.consume()
- }
- Orientation.Vertical ->
- verticalDrag(drag.id) {
- onDrag(controller, it, it.positionChange().toFloat())
- it.consume()
- }
- }
+ drag(
+ initialPointerId = drag.id,
+ hasDragged = { it.positionChangeIgnoreConsumed().toFloat() != 0f },
+ onDrag = {
+ onDrag(controller, it, it.positionChange().toFloat())
+ it.consume()
+ },
+ onIgnoredEvent = {
+ // We are still dragging an object, but this event is not of interest to
+ // the caller.
+ // This event will not trigger the onDrag event, but we will consume the
+ // event to prevent another pointerInput from interrupting the current
+ // gesture just because the event was ignored.
+ it.consume()
+ },
+ )
} catch (t: Throwable) {
onDragCancel(controller)
throw t
@@ -322,7 +343,9 @@
}
}
- private suspend fun AwaitPointerEventScope.awaitConsumableEvent(): PointerEvent {
+ private suspend fun AwaitPointerEventScope.awaitConsumableEvent(
+ pass: () -> PointerEventPass,
+ ): PointerEvent {
fun canBeConsumed(changes: List<PointerInputChange>): Boolean {
// All pointers must be:
return changes.fastAll {
@@ -337,9 +360,7 @@
var event: PointerEvent
do {
- // To allow the descendants with the opportunity to consume the event, we wait for it in
- // the Main pass.
- event = awaitPointerEvent()
+ event = awaitPointerEvent(pass = pass())
} while (!canBeConsumed(event.changes))
// We found a consumable event in the Main pass
@@ -352,4 +373,82 @@
Orientation.Horizontal -> x
}
}
+
+ /**
+ * Continues to read drag events until all pointers are up or the drag event is canceled. The
+ * initial pointer to use for driving the drag is [initialPointerId]. [hasDragged] passes the
+ * result whether a change was detected from the drag function or not.
+ *
+ * Whenever the pointer moves, if [hasDragged] returns true, [onDrag] is called; otherwise,
+ * [onIgnoredEvent] is called.
+ *
+ * @return true when gesture ended with all pointers up and false when the gesture was canceled.
+ *
+ * Note: Inspired by DragGestureDetector.kt
+ */
+ private suspend inline fun AwaitPointerEventScope.drag(
+ initialPointerId: PointerId,
+ hasDragged: (PointerInputChange) -> Boolean,
+ onDrag: (PointerInputChange) -> Unit,
+ onIgnoredEvent: (PointerInputChange) -> Unit,
+ ): Boolean {
+ val pointer = currentEvent.changes.fastFirstOrNull { it.id == initialPointerId }
+ val isPointerUp = pointer?.pressed != true
+ if (isPointerUp) {
+ return false // The pointer has already been lifted, so the gesture is canceled
+ }
+ var pointerId = initialPointerId
+ while (true) {
+ val change = awaitDragOrUp(pointerId, hasDragged, onIgnoredEvent) ?: return false
+
+ if (change.isConsumed) {
+ return false
+ }
+
+ if (change.changedToUpIgnoreConsumed()) {
+ return true
+ }
+
+ onDrag(change)
+ pointerId = change.id
+ }
+ }
+
+ /**
+ * Waits for a single drag in one axis, final pointer up, or all pointers are up. When
+ * [initialPointerId] has lifted, another pointer that is down is chosen to be the finger
+ * governing the drag. When the final pointer is lifted, that [PointerInputChange] is returned.
+ * When a drag is detected, that [PointerInputChange] is returned. A drag is only detected when
+ * [hasDragged] returns `true`. Events that should not be captured are passed to
+ * [onIgnoredEvent].
+ *
+ * `null` is returned if there was an error in the pointer input stream and the pointer that was
+ * down was dropped before the 'up' was received.
+ *
+ * Note: Inspired by DragGestureDetector.kt
+ */
+ private suspend inline fun AwaitPointerEventScope.awaitDragOrUp(
+ initialPointerId: PointerId,
+ hasDragged: (PointerInputChange) -> Boolean,
+ onIgnoredEvent: (PointerInputChange) -> Unit,
+ ): PointerInputChange? {
+ var pointerId = initialPointerId
+ while (true) {
+ val event = awaitPointerEvent()
+ val dragEvent = event.changes.fastFirstOrNull { it.id == pointerId } ?: return null
+ if (dragEvent.changedToUpIgnoreConsumed()) {
+ val otherDown = event.changes.fastFirstOrNull { it.pressed }
+ if (otherDown == null) {
+ // This is the last "up"
+ return dragEvent
+ } else {
+ pointerId = otherDown.id
+ }
+ } else if (hasDragged(dragEvent)) {
+ return dragEvent
+ } else {
+ onIgnoredEvent(dragEvent)
+ }
+ }
+ }
}
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 f32720c..7ea8cbd 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
@@ -293,7 +293,15 @@
width = fromSize.width
height = fromSize.height
} else {
- val size = lerp(fromSize, toSize, transition.progress)
+ val overscrollSpec = transition.currentOverscrollSpec
+ val progress =
+ when {
+ overscrollSpec == null -> transition.progress
+ overscrollSpec.scene == transition.toScene -> 1f
+ else -> 0f
+ }
+
+ val size = lerp(fromSize, toSize, progress)
width = size.width.coerceAtLeast(0)
height = size.height.coerceAtLeast(0)
}
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/AnimatedSharedAsStateTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/AnimatedSharedAsStateTest.kt
index 6e8b208..a7889e2 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/AnimatedSharedAsStateTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/AnimatedSharedAsStateTest.kt
@@ -18,10 +18,13 @@
import androidx.compose.animation.core.LinearEasing
import androidx.compose.animation.core.tween
+import androidx.compose.foundation.gestures.Orientation
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.SideEffect
import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.setValue
import androidx.compose.runtime.snapshotFlow
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
@@ -443,4 +446,56 @@
assertThat(lastValues[bar]?.get(SceneC)).isWithin(0.001f).of(7f)
assertThat(lastValues[bar]?.get(SceneD)).isWithin(0.001f).of(7f)
}
+
+ @Test
+ fun animatedValueDoesNotOverscrollWhenOverscrollIsSpecified() {
+ val state =
+ rule.runOnUiThread {
+ MutableSceneTransitionLayoutStateImpl(
+ SceneA,
+ transitions { overscroll(SceneB, Orientation.Horizontal) }
+ )
+ }
+
+ val key = ValueKey("foo")
+ val lastValues = mutableMapOf<SceneKey, Float>()
+
+ @Composable
+ fun SceneScope.animateFloat(value: Float, key: ValueKey) {
+ val animatedValue = animateSceneFloatAsState(value, key)
+ LaunchedEffect(animatedValue) {
+ snapshotFlow { animatedValue.value }.collect { lastValues[sceneKey] = it }
+ }
+ }
+
+ rule.setContent {
+ SceneTransitionLayout(state) {
+ scene(SceneA) { animateFloat(0f, key) }
+ scene(SceneB) { animateFloat(100f, key) }
+ }
+ }
+
+ // Overscroll on A at -100%: value should be interpolated given that there is no overscroll
+ // defined for scene A.
+ var progress by mutableStateOf(-1f)
+ rule.runOnIdle {
+ state.startTransition(transition(from = SceneA, to = SceneB, progress = { progress }))
+ }
+ rule.waitForIdle()
+ assertThat(lastValues[SceneA]).isWithin(0.001f).of(-100f)
+ assertThat(lastValues[SceneB]).isWithin(0.001f).of(-100f)
+
+ // Middle of the transition.
+ progress = 0.5f
+ rule.waitForIdle()
+ assertThat(lastValues[SceneA]).isWithin(0.001f).of(50f)
+ assertThat(lastValues[SceneB]).isWithin(0.001f).of(50f)
+
+ // Overscroll on B at 200%: value should not be interpolated given that there is an
+ // overscroll defined for scene B.
+ progress = 2f
+ rule.waitForIdle()
+ assertThat(lastValues[SceneA]).isWithin(0.001f).of(100f)
+ assertThat(lastValues[SceneB]).isWithin(0.001f).of(100f)
+ }
}
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MultiPointerDraggableTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MultiPointerDraggableTest.kt
index 4bb643f..1a0740b 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MultiPointerDraggableTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MultiPointerDraggableTest.kt
@@ -349,6 +349,121 @@
}
@Test
+ fun multiPointerDuringAnotherGestureWaitAConsumableEventAfterMainPass() {
+ val size = 200f
+ val middle = Offset(size / 2f, size / 2f)
+
+ var verticalStarted = false
+ var verticalDragged = false
+ var verticalStopped = false
+ var horizontalStarted = false
+ var horizontalDragged = false
+ var horizontalStopped = false
+
+ var touchSlop = 0f
+ rule.setContent {
+ touchSlop = LocalViewConfiguration.current.touchSlop
+ Box(
+ Modifier.size(with(LocalDensity.current) { Size(size, size).toDpSize() })
+ .multiPointerDraggable(
+ orientation = Orientation.Vertical,
+ enabled = { true },
+ startDragImmediately = { false },
+ onDragStarted = { _, _, _ ->
+ verticalStarted = true
+ object : DragController {
+ override fun onDrag(delta: Float) {
+ verticalDragged = true
+ }
+
+ override fun onStop(velocity: Float, canChangeScene: Boolean) {
+ verticalStopped = true
+ }
+ }
+ },
+ )
+ .multiPointerDraggable(
+ orientation = Orientation.Horizontal,
+ enabled = { true },
+ startDragImmediately = { false },
+ onDragStarted = { _, _, _ ->
+ horizontalStarted = true
+ object : DragController {
+ override fun onDrag(delta: Float) {
+ horizontalDragged = true
+ }
+
+ override fun onStop(velocity: Float, canChangeScene: Boolean) {
+ horizontalStopped = true
+ }
+ }
+ },
+ )
+ )
+ }
+
+ fun startDraggingDown() {
+ rule.onRoot().performTouchInput {
+ down(middle)
+ moveBy(Offset(0f, touchSlop))
+ }
+ }
+
+ fun startDraggingRight() {
+ rule.onRoot().performTouchInput {
+ down(middle)
+ moveBy(Offset(touchSlop, 0f))
+ }
+ }
+
+ fun stopDragging() {
+ rule.onRoot().performTouchInput { up() }
+ }
+
+ fun continueDown() {
+ rule.onRoot().performTouchInput { moveBy(Offset(0f, touchSlop)) }
+ }
+
+ fun continueRight() {
+ rule.onRoot().performTouchInput { moveBy(Offset(touchSlop, 0f)) }
+ }
+
+ startDraggingDown()
+ assertThat(verticalStarted).isTrue()
+ assertThat(verticalDragged).isTrue()
+ assertThat(verticalStopped).isFalse()
+
+ // Ignore right swipe, do not interrupt the dragging gesture.
+ continueRight()
+ assertThat(horizontalStarted).isFalse()
+ assertThat(horizontalDragged).isFalse()
+ assertThat(horizontalStopped).isFalse()
+ assertThat(verticalStopped).isFalse()
+
+ stopDragging()
+ assertThat(verticalStopped).isTrue()
+
+ verticalStarted = false
+ verticalDragged = false
+ verticalStopped = false
+
+ startDraggingRight()
+ assertThat(horizontalStarted).isTrue()
+ assertThat(horizontalDragged).isTrue()
+ assertThat(horizontalStopped).isFalse()
+
+ // Ignore down swipe, do not interrupt the dragging gesture.
+ continueDown()
+ assertThat(verticalStarted).isFalse()
+ assertThat(verticalDragged).isFalse()
+ assertThat(verticalStopped).isFalse()
+ assertThat(horizontalStopped).isFalse()
+
+ stopDragging()
+ assertThat(horizontalStopped).isTrue()
+ }
+
+ @Test
fun multiPointerSwipeDetectorInteraction() {
val size = 200f
val middle = Offset(size / 2f, size / 2f)
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutTest.kt
index 08532bd..a8dd572 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutTest.kt
@@ -21,6 +21,7 @@
import androidx.compose.animation.core.LinearEasing
import androidx.compose.animation.core.tween
import androidx.compose.foundation.background
+import androidx.compose.foundation.gestures.Orientation
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.offset
@@ -333,6 +334,42 @@
}
@Test
+ fun layoutSizeDoesNotOverscrollWhenOverscrollIsSpecified() {
+ val state =
+ rule.runOnUiThread {
+ MutableSceneTransitionLayoutStateImpl(
+ SceneA,
+ transitions { overscroll(SceneB, Orientation.Horizontal) }
+ )
+ }
+
+ val layoutTag = "layout"
+ rule.setContent {
+ SceneTransitionLayout(state, Modifier.testTag(layoutTag)) {
+ scene(SceneA) { Box(Modifier.size(50.dp)) }
+ scene(SceneB) { Box(Modifier.size(70.dp)) }
+ }
+ }
+
+ // Overscroll on A at -100%: size should be interpolated given that there is no overscroll
+ // defined for scene A.
+ var progress by mutableStateOf(-1f)
+ rule.runOnIdle {
+ state.startTransition(transition(from = SceneA, to = SceneB, progress = { progress }))
+ }
+ rule.onNodeWithTag(layoutTag).assertSizeIsEqualTo(30.dp)
+
+ // Middle of the transition.
+ progress = 0.5f
+ rule.onNodeWithTag(layoutTag).assertSizeIsEqualTo(60.dp)
+
+ // Overscroll on B at 200%: size should not be interpolated given that there is an
+ // overscroll defined for scene B.
+ progress = 2f
+ rule.onNodeWithTag(layoutTag).assertSizeIsEqualTo(70.dp)
+ }
+
+ @Test
fun multipleTransitionsWillComposeMultipleScenes() {
val duration = 10 * 16L
diff --git a/packages/SystemUI/flag_check.py b/packages/SystemUI/flag_check.py
index 95a25c5..d78ef5a 100755
--- a/packages/SystemUI/flag_check.py
+++ b/packages/SystemUI/flag_check.py
@@ -52,7 +52,7 @@
nargs='?',
default='',
help=
- 'REPO_PATH in repo upload to determine whether the check should run for this project.')
+ 'REPO_PROJECT in repo upload to determine whether the check should run for this project.')
# Parse the arguments
args = parser.parse_args()
@@ -112,16 +112,16 @@
sys.exit(0)
-def should_run_path(path, files):
+def should_run_path(project, files):
"""Returns a boolean if this check should run with these paths.
If you want to check for a particular subdirectory under the path,
add a check here, call should_run_files and check for a specific sub dir path in should_run_files.
"""
- if not path:
+ if not project:
return False
- if path == 'frameworks/base':
+ if project == 'platform/frameworks/base':
return should_run_files(files)
- # Default case, run for all other paths which calls this script.
+ # Default case, run for all other projects which calls this script.
return True
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/ambient/statusbar/ui/AmbientStatusBarViewControllerTest.java
similarity index 87%
rename from packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/ambient/statusbar/ui/AmbientStatusBarViewControllerTest.java
index f561c53..d84d151 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/ambient/statusbar/ui/AmbientStatusBarViewControllerTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 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,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.dreams;
+package com.android.systemui.ambient.statusbar.ui;
import static android.app.StatusBarManager.WINDOW_STATE_HIDDEN;
import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
@@ -44,6 +44,10 @@
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.dreams.DreamOverlayNotificationCountProvider;
+import com.android.systemui.dreams.DreamOverlayStateController;
+import com.android.systemui.dreams.DreamOverlayStatusBarItemsProvider;
+import com.android.systemui.kosmos.KosmosJavaAdapter;
import com.android.systemui.log.LogBuffer;
import com.android.systemui.log.core.FakeLogBuffer;
import com.android.systemui.res.R;
@@ -54,7 +58,6 @@
import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.statusbar.window.StatusBarWindowStateController;
import com.android.systemui.statusbar.window.StatusBarWindowStateListener;
-import com.android.systemui.touch.TouchInsetManager;
import com.android.systemui.util.time.DateFormatUtil;
import org.junit.Before;
@@ -72,14 +75,12 @@
@SmallTest
@TestableLooper.RunWithLooper(setAsMainLooper = true)
@RunWith(AndroidJUnit4.class)
-public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase {
+public class AmbientStatusBarViewControllerTest extends SysuiTestCase {
private static final String NOTIFICATION_INDICATOR_FORMATTER_STRING =
"{count, plural, =1 {# notification} other {# notifications}}";
@Mock
- MockDreamOverlayStatusBarView mView;
- @Mock
- TouchInsetManager.TouchInsetSession mTouchSession;
+ MockAmbientStatusBarView mView;
@Mock
Resources mResources;
@Mock
@@ -114,9 +115,11 @@
private final Executor mMainExecutor = Runnable::run;
- private final FakeWifiRepository mWifiRepository = new FakeWifiRepository();
+ private final KosmosJavaAdapter mKosmos = new KosmosJavaAdapter(this);
- DreamOverlayStatusBarViewController mController;
+ private final FakeWifiRepository mWifiRepository = mKosmos.getFakeWifiRepository();
+
+ AmbientStatusBarViewController mController;
@Before
public void setup() {
@@ -128,11 +131,10 @@
doCallRealMethod().when(mView).getVisibility();
when(mUserTracker.getUserId()).thenReturn(ActivityManager.getCurrentUser());
- mController = new DreamOverlayStatusBarViewController(
+ mController = new AmbientStatusBarViewController(
mView,
mResources,
mMainExecutor,
- mTouchSession,
mAlarmManager,
mNextAlarmController,
mDateFormatUtil,
@@ -143,7 +145,7 @@
mDreamOverlayStatusBarItemsProvider,
mDreamOverlayStateController,
mUserTracker,
- mWifiRepository,
+ mKosmos.getWifiInteractor(),
mLogBuffer);
}
@@ -164,7 +166,7 @@
mController.updateWifiUnavailableStatusIcon(false);
verify(mView).showIcon(
- DreamOverlayStatusBarView.STATUS_ICON_WIFI_UNAVAILABLE, true, null);
+ AmbientStatusBarView.STATUS_ICON_WIFI_UNAVAILABLE, true, null);
}
@Test
@@ -173,7 +175,7 @@
mController.updateWifiUnavailableStatusIcon(true);
verify(mView).showIcon(
- DreamOverlayStatusBarView.STATUS_ICON_WIFI_UNAVAILABLE, false, null);
+ AmbientStatusBarView.STATUS_ICON_WIFI_UNAVAILABLE, false, null);
}
@Test
@@ -183,7 +185,7 @@
when(mAlarmManager.getNextAlarmClock(anyInt())).thenReturn(alarmClockInfo);
mController.onViewAttached();
verify(mView).showIcon(
- eq(DreamOverlayStatusBarView.STATUS_ICON_ALARM_SET), eq(true), any());
+ eq(AmbientStatusBarView.STATUS_ICON_ALARM_SET), eq(true), any());
}
@Test
@@ -191,7 +193,7 @@
when(mAlarmManager.getNextAlarmClock(anyInt())).thenReturn(null);
mController.onViewAttached();
verify(mView).showIcon(
- eq(DreamOverlayStatusBarView.STATUS_ICON_ALARM_SET), eq(false), isNull());
+ eq(AmbientStatusBarView.STATUS_ICON_ALARM_SET), eq(false), isNull());
}
@Test
@@ -202,7 +204,7 @@
.thenReturn(false);
mController.onViewAttached();
verify(mView).showIcon(
- DreamOverlayStatusBarView.STATUS_ICON_MIC_DISABLED, true, null);
+ AmbientStatusBarView.STATUS_ICON_MIC_DISABLED, true, null);
}
@Test
@@ -213,7 +215,7 @@
.thenReturn(true);
mController.onViewAttached();
verify(mView).showIcon(
- DreamOverlayStatusBarView.STATUS_ICON_CAMERA_DISABLED, true, null);
+ AmbientStatusBarView.STATUS_ICON_CAMERA_DISABLED, true, null);
}
@Test
@@ -224,7 +226,7 @@
.thenReturn(true);
mController.onViewAttached();
verify(mView).showIcon(
- DreamOverlayStatusBarView.STATUS_ICON_MIC_CAMERA_DISABLED, true, null);
+ AmbientStatusBarView.STATUS_ICON_MIC_CAMERA_DISABLED, true, null);
}
@Test
@@ -237,7 +239,7 @@
callbackCapture.getValue().onNotificationCountChanged(1);
verify(mView).showIcon(
- eq(DreamOverlayStatusBarView.STATUS_ICON_NOTIFICATIONS), eq(true), any());
+ eq(AmbientStatusBarView.STATUS_ICON_NOTIFICATIONS), eq(true), any());
}
@Test
@@ -250,16 +252,15 @@
callbackCapture.getValue().onNotificationCountChanged(0);
verify(mView).showIcon(
- eq(DreamOverlayStatusBarView.STATUS_ICON_NOTIFICATIONS), eq(false), isNull());
+ eq(AmbientStatusBarView.STATUS_ICON_NOTIFICATIONS), eq(false), isNull());
}
@Test
public void testNotificationsIconNotShownWhenCountProviderAbsent() {
- DreamOverlayStatusBarViewController controller = new DreamOverlayStatusBarViewController(
+ AmbientStatusBarViewController controller = new AmbientStatusBarViewController(
mView,
mResources,
mMainExecutor,
- mTouchSession,
mAlarmManager,
mNextAlarmController,
mDateFormatUtil,
@@ -270,11 +271,11 @@
mDreamOverlayStatusBarItemsProvider,
mDreamOverlayStateController,
mUserTracker,
- mWifiRepository,
+ mKosmos.getWifiInteractor(),
mLogBuffer);
controller.onViewAttached();
verify(mView, never()).showIcon(
- eq(DreamOverlayStatusBarView.STATUS_ICON_NOTIFICATIONS), eq(true), any());
+ eq(AmbientStatusBarView.STATUS_ICON_NOTIFICATIONS), eq(true), any());
}
@Test
@@ -283,7 +284,7 @@
Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS);
mController.onViewAttached();
verify(mView).showIcon(
- DreamOverlayStatusBarView.STATUS_ICON_PRIORITY_MODE_ON, true, null);
+ AmbientStatusBarView.STATUS_ICON_PRIORITY_MODE_ON, true, null);
}
@Test
@@ -292,7 +293,7 @@
Settings.Global.ZEN_MODE_OFF);
mController.onViewAttached();
verify(mView).showIcon(
- DreamOverlayStatusBarView.STATUS_ICON_PRIORITY_MODE_ON, false, null);
+ AmbientStatusBarView.STATUS_ICON_PRIORITY_MODE_ON, false, null);
}
@Test
@@ -322,7 +323,7 @@
callbackCapture.getValue().onNotificationCountChanged(1);
verify(mView).showIcon(
- eq(DreamOverlayStatusBarView.STATUS_ICON_NOTIFICATIONS), eq(true), any());
+ eq(AmbientStatusBarView.STATUS_ICON_NOTIFICATIONS), eq(true), any());
}
@Test
@@ -335,7 +336,7 @@
callbackCapture.getValue().onNotificationCountChanged(0);
verify(mView).showIcon(
- eq(DreamOverlayStatusBarView.STATUS_ICON_NOTIFICATIONS), eq(false), any());
+ eq(AmbientStatusBarView.STATUS_ICON_NOTIFICATIONS), eq(false), any());
}
@Test
@@ -354,7 +355,7 @@
SensorPrivacyManager.Sensors.MICROPHONE, true);
verify(mView).showIcon(
- DreamOverlayStatusBarView.STATUS_ICON_MIC_CAMERA_DISABLED, true, null);
+ AmbientStatusBarView.STATUS_ICON_MIC_CAMERA_DISABLED, true, null);
}
@Test
@@ -369,7 +370,7 @@
callbackCapture.getValue().onZenChanged(Settings.Global.ZEN_MODE_NO_INTERRUPTIONS);
verify(mView).showIcon(
- DreamOverlayStatusBarView.STATUS_ICON_PRIORITY_MODE_ON, true, null);
+ AmbientStatusBarView.STATUS_ICON_PRIORITY_MODE_ON, true, null);
}
@Test
@@ -384,7 +385,7 @@
callbackCapture.getValue().onZenChanged(Settings.Global.ZEN_MODE_OFF);
verify(mView).showIcon(
- DreamOverlayStatusBarView.STATUS_ICON_PRIORITY_MODE_ON, false, null);
+ AmbientStatusBarView.STATUS_ICON_PRIORITY_MODE_ON, false, null);
}
@Test
@@ -399,7 +400,7 @@
callbackCapture.getValue().onStateChanged();
verify(mView).showIcon(
- DreamOverlayStatusBarView.STATUS_ICON_ASSISTANT_ATTENTION_ACTIVE, true, null);
+ AmbientStatusBarView.STATUS_ICON_ASSISTANT_ATTENTION_ACTIVE, true, null);
}
@Test
@@ -460,7 +461,7 @@
final ArgumentCaptor<DreamOverlayStatusBarItemsProvider.Callback>
callbackCapture = ArgumentCaptor.forClass(
- DreamOverlayStatusBarItemsProvider.Callback.class);
+ DreamOverlayStatusBarItemsProvider.Callback.class);
verify(mDreamOverlayStatusBarItemsProvider).addCallback(callbackCapture.capture());
callbackCapture.getValue().onStatusBarItemsChanged(List.of(mStatusBarItem));
@@ -532,10 +533,10 @@
callback.onStateChanged();
}
- private static class MockDreamOverlayStatusBarView extends DreamOverlayStatusBarView {
+ private static class MockAmbientStatusBarView extends AmbientStatusBarView {
private int mVisibility = View.VISIBLE;
- private MockDreamOverlayStatusBarView(Context context) {
+ private MockAmbientStatusBarView(Context context) {
super(context);
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/ambient/touch/ShadeTouchHandlerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/ambient/touch/ShadeTouchHandlerTest.java
index 04b930e..07d8890 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/ambient/touch/ShadeTouchHandlerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/ambient/touch/ShadeTouchHandlerTest.java
@@ -25,12 +25,15 @@
import static org.mockito.Mockito.when;
import android.app.DreamManager;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
import android.view.GestureDetector;
import android.view.MotionEvent;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
+import com.android.systemui.Flags;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.shade.ShadeViewController;
import com.android.systemui.shared.system.InputChannelCompat;
@@ -87,7 +90,7 @@
assertThat(captured).isTrue();
}
- // Verifies that a swipe in the upward direction is not catpured.
+ // Verifies that a swipe in the upward direction is not captured.
@Test
public void testSwipeUp_notCaptured() {
final boolean captured = swipe(Direction.UP);
@@ -98,34 +101,58 @@
// Verifies that a swipe down forwards captured touches to central surfaces for handling.
@Test
- public void testSwipeDown_sentToCentralSurfaces() {
+ @EnableFlags(Flags.FLAG_COMMUNAL_HUB)
+ public void testSwipeDown_communalEnabled_sentToCentralSurfaces() {
swipe(Direction.DOWN);
- // Both motion events are sent for the shade window to process.
+ // Both motion events are sent for central surfaces to process.
verify(mCentralSurfaces, times(2)).handleExternalShadeWindowTouch(any());
}
- // Verifies that a swipe down forwards captured touches to central surfaces for handling.
+ // Verifies that a swipe down forwards captured touches to the shade view for handling.
+ @Test
+ @DisableFlags(Flags.FLAG_COMMUNAL_HUB)
+ public void testSwipeDown_communalDisabled_sentToShadeView() {
+ swipe(Direction.DOWN);
+
+ // Both motion events are sent for the shade view to process.
+ verify(mShadeViewController, times(2)).handleExternalTouch(any());
+ }
+
+ // Verifies that a swipe down while dreaming forwards captured touches to the shade view for
+ // handling.
@Test
public void testSwipeDown_dreaming_sentToShadeView() {
when(mDreamManager.isDreaming()).thenReturn(true);
swipe(Direction.DOWN);
- // Both motion events are sent for the shade window to process.
+ // Both motion events are sent for the shade view to process.
verify(mShadeViewController, times(2)).handleExternalTouch(any());
}
- // Verifies that a swipe down is not forwarded to the shade window.
+ // Verifies that a swipe up is not forwarded to central surfaces.
@Test
- public void testSwipeUp_touchesNotSent() {
+ @EnableFlags(Flags.FLAG_COMMUNAL_HUB)
+ public void testSwipeUp_communalEnabled_touchesNotSent() {
swipe(Direction.UP);
- // Motion events are not sent for the shade window to process as the swipe is going in the
+ // Motion events are not sent for central surfaces to process as the swipe is going in the
// wrong direction.
verify(mCentralSurfaces, never()).handleExternalShadeWindowTouch(any());
}
+ // Verifies that a swipe up is not forwarded to the shade view.
+ @Test
+ @DisableFlags(Flags.FLAG_COMMUNAL_HUB)
+ public void testSwipeUp_communalDisabled_touchesNotSent() {
+ swipe(Direction.UP);
+
+ // Motion events are not sent for the shade view to process as the swipe is going in the
+ // wrong direction.
+ verify(mShadeViewController, never()).handleExternalTouch(any());
+ }
+
/**
* Simulates a swipe in the given direction and returns true if the touch was intercepted by the
* touch handler's gesture listener.
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/BiometricTestExtensions.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/BiometricTestExtensions.kt
index 9c2791f..75a77cf 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/BiometricTestExtensions.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/BiometricTestExtensions.kt
@@ -131,8 +131,9 @@
negativeButton: String = "neg",
): PromptInfo {
val info = PromptInfo()
- info.logoRes = logoRes
- info.logoBitmap = logoBitmap
+ if (logoBitmap != null) {
+ info.setLogo(logoRes, logoBitmap)
+ }
info.logoDescription = logoDescription
info.title = title
info.subtitle = subtitle
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerWithCoroutinesTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerWithCoroutinesTest.kt
index ab55125..29a6e56 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerWithCoroutinesTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerWithCoroutinesTest.kt
@@ -235,6 +235,7 @@
job.cancel()
}
+
@Test
fun fadeFromDialogSuggestedAlpha() =
testScope.runTest {
@@ -511,9 +512,10 @@
testScope.runTest {
// GIVEN view is attached
mController.onViewAttached()
+ val job = mController.listenForLockscreenAodTransitions(this)
+ runCurrent()
Mockito.reset(mView)
- val job = mController.listenForLockscreenAodTransitions(this)
// WHEN aod to lockscreen transition is cancelled
transitionRepository.sendTransitionStep(
TransitionStep(
@@ -537,7 +539,7 @@
// THEN doze amount is updated to zero
verify(mView)
- .onDozeAmountChanged(eq(0f), eq(0f), eq(UdfpsKeyguardViewLegacy.ANIMATION_NONE))
+ .onDozeAmountChanged(eq(0f), eq(0f), eq(ANIMATION_BETWEEN_AOD_AND_LOCKSCREEN))
job.cancel()
}
@@ -546,9 +548,10 @@
testScope.runTest {
// GIVEN view is attached
mController.onViewAttached()
+ val job = mController.listenForLockscreenAodTransitions(this)
+ runCurrent()
Mockito.reset(mView)
- val job = mController.listenForLockscreenAodTransitions(this)
// WHEN lockscreen to aod transition is cancelled
transitionRepository.sendTransitionStep(
TransitionStep(
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalDreamStartableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalDreamStartableTest.kt
index bfed33c..fe683e07 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalDreamStartableTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalDreamStartableTest.kt
@@ -22,7 +22,6 @@
import androidx.test.filters.SmallTest
import com.android.systemui.Flags
import com.android.systemui.SysuiTestCase
-import com.android.systemui.communal.domain.interactor.communalInteractor
import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
import com.android.systemui.keyguard.data.repository.keyguardRepository
@@ -66,7 +65,6 @@
powerInteractor = kosmos.powerInteractor,
keyguardInteractor = kosmos.keyguardInteractor,
keyguardTransitionInteractor = kosmos.keyguardTransitionInteractor,
- communalInteractor = kosmos.communalInteractor,
dreamManager = dreamManager,
bgScope = kosmos.applicationCoroutineScope,
)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalSceneInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalSceneInteractorTest.kt
index aad2e60..a0e7781 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalSceneInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalSceneInteractorTest.kt
@@ -20,6 +20,7 @@
import androidx.test.filters.SmallTest
import com.android.compose.animation.scene.ObservableTransitionState
import com.android.systemui.SysuiTestCase
+import com.android.systemui.animation.ActivityTransitionAnimator
import com.android.systemui.communal.data.repository.communalSceneRepository
import com.android.systemui.communal.domain.model.CommunalTransitionProgressModel
import com.android.systemui.communal.shared.model.CommunalScenes
@@ -27,8 +28,10 @@
import com.android.systemui.kosmos.testScope
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.test.advanceTimeBy
import kotlinx.coroutines.test.runTest
import org.junit.Test
import org.junit.runner.RunWith
@@ -63,6 +66,21 @@
assertThat(currentScene).isEqualTo(CommunalScenes.Communal)
}
+ @OptIn(ExperimentalCoroutinesApi::class)
+ @Test
+ fun snapToSceneWithDelay() =
+ testScope.runTest {
+ val currentScene by collectLastValue(underTest.currentScene)
+ assertThat(currentScene).isEqualTo(CommunalScenes.Blank)
+ underTest.snapToScene(
+ CommunalScenes.Communal,
+ ActivityTransitionAnimator.TIMINGS.totalDuration
+ )
+ assertThat(currentScene).isEqualTo(CommunalScenes.Blank)
+ advanceTimeBy(ActivityTransitionAnimator.TIMINGS.totalDuration)
+ assertThat(currentScene).isEqualTo(CommunalScenes.Communal)
+ }
+
@Test
fun transitionProgress_fullProgress() =
testScope.runTest {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/WidgetInteractionHandlerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/WidgetInteractionHandlerTest.kt
index 420b11c..df7b291 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/WidgetInteractionHandlerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/WidgetInteractionHandlerTest.kt
@@ -27,23 +27,19 @@
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.plugins.ActivityStarter
-import com.android.systemui.util.mockito.eq
-import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-import org.mockito.ArgumentMatchers.refEq
-import org.mockito.Mock
-import org.mockito.Mockito.isNull
-import org.mockito.Mockito.notNull
-import org.mockito.Mockito.verify
-import org.mockito.MockitoAnnotations
+import org.mockito.kotlin.eq
+import org.mockito.kotlin.isNull
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.notNull
+import org.mockito.kotlin.refEq
+import org.mockito.kotlin.verify
@SmallTest
@RunWith(AndroidJUnit4::class)
class WidgetInteractionHandlerTest : SysuiTestCase() {
- @Mock private lateinit var activityStarter: ActivityStarter
-
- private lateinit var underTest: WidgetInteractionHandler
+ private val activityStarter = mock<ActivityStarter>()
private val testIntent =
PendingIntent.getActivity(
@@ -54,10 +50,8 @@
)
private val testResponse = RemoteResponse.fromPendingIntent(testIntent)
- @Before
- fun setUp() {
- MockitoAnnotations.initMocks(this)
- underTest = WidgetInteractionHandler(activityStarter)
+ private val underTest: WidgetInteractionHandler by lazy {
+ WidgetInteractionHandler(activityStarter)
}
@Test
@@ -81,6 +75,26 @@
}
@Test
+ fun launchAnimatorIsUsedForSmartspaceView() {
+ val parent = FrameLayout(context)
+ val view = SmartspaceAppWidgetHostView(context)
+ parent.addView(view)
+ val (fillInIntent, activityOptions) = testResponse.getLaunchOptions(view)
+
+ underTest.onInteraction(view, testIntent, testResponse)
+
+ verify(activityStarter)
+ .startPendingIntentMaybeDismissingKeyguard(
+ eq(testIntent),
+ eq(false),
+ isNull(),
+ notNull(),
+ refEq(fillInIntent),
+ refEq(activityOptions.toBundle()),
+ )
+ }
+
+ @Test
fun launchAnimatorIsNotUsedForRegularView() {
val parent = FrameLayout(context)
val view = View(context)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt
index 86fdaa5..73ef775 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt
@@ -7,6 +7,7 @@
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.ambient.statusbar.ui.AmbientStatusBarViewController
import com.android.systemui.complication.ComplicationHostViewController
import com.android.systemui.dreams.ui.viewmodel.DreamViewModel
import com.android.systemui.log.core.FakeLogBuffer
@@ -43,7 +44,7 @@
@Mock private lateinit var mockAnimator: AnimatorSet
@Mock private lateinit var blurUtils: BlurUtils
@Mock private lateinit var hostViewController: ComplicationHostViewController
- @Mock private lateinit var statusBarViewController: DreamOverlayStatusBarViewController
+ @Mock private lateinit var statusBarViewController: AmbientStatusBarViewController
@Mock private lateinit var stateController: DreamOverlayStateController
@Mock private lateinit var transitionViewModel: DreamViewModel
private val logBuffer = FakeLogBuffer.Factory.create()
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 f5c86e0..c48ced1 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java
@@ -17,6 +17,7 @@
package com.android.systemui.dreams;
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;
@@ -47,6 +48,7 @@
import com.android.keyguard.BouncerPanelExpansionCalculator;
import com.android.systemui.Flags;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.ambient.statusbar.ui.AmbientStatusBarViewController;
import com.android.systemui.ambient.touch.scrim.BouncerlessScrimController;
import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerCallbackInteractor;
import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerCallbackInteractor.PrimaryBouncerExpansionCallback;
@@ -55,6 +57,7 @@
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
import com.android.systemui.shade.domain.interactor.ShadeInteractor;
import com.android.systemui.statusbar.BlurUtils;
+import com.android.systemui.touch.TouchInsetManager;
import kotlinx.coroutines.CoroutineDispatcher;
@@ -80,7 +83,7 @@
ViewTreeObserver mViewTreeObserver;
@Mock
- DreamOverlayStatusBarViewController mDreamOverlayStatusBarViewController;
+ AmbientStatusBarViewController mAmbientStatusBarViewController;
@Mock
LowLightTransitionCoordinator mLowLightTransitionCoordinator;
@@ -131,6 +134,8 @@
CommunalInteractor mCommunalInteractor;
@Mock
private DreamManager mDreamManager;
+ @Mock
+ private TouchInsetManager.TouchInsetSession mTouchInsetSession;
DreamOverlayContainerViewController mController;
@@ -144,14 +149,17 @@
when(mDreamOverlayContainerView.getRootSurfaceControl())
.thenReturn(mAttachedSurfaceControl);
when(mKeyguardTransitionInteractor.isFinishedInStateWhere(any())).thenReturn(emptyFlow());
+ when(mShadeInteractor.isAnyExpanded()).thenReturn(MutableStateFlow(false));
+ when(mCommunalInteractor.isCommunalShowing()).thenReturn(MutableStateFlow(false));
mController = new DreamOverlayContainerViewController(
mDreamOverlayContainerView,
mComplicationHostViewController,
mDreamOverlayContentView,
mHubGestureIndicatorView,
- mDreamOverlayStatusBarViewController,
+ mAmbientStatusBarViewController,
mLowLightTransitionCoordinator,
+ mTouchInsetSession,
mBlurUtils,
mHandler,
mDispatcher,
@@ -190,7 +198,7 @@
@Test
public void testDreamOverlayStatusBarViewControllerInitialized() {
mController.init();
- verify(mDreamOverlayStatusBarViewController).init();
+ verify(mAmbientStatusBarViewController).init();
}
@Test
@@ -325,4 +333,12 @@
mController.onViewDetached();
verify(mBouncerlessScrimController).removeCallback(any());
}
+
+ @EnableFlags(android.service.dreams.Flags.FLAG_DREAM_HANDLES_BEING_OBSCURED)
+ @Test
+ public void testOnViewAttachedSucceedsWhenDreamHandlesBeingObscuredFlagEnabled() {
+ // This test will catch failures in presubmit when the dream_handles_being_obscured flag is
+ // enabled.
+ mController.onViewAttached();
+ }
}
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 c51413a..3d3c778 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,26 +21,35 @@
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
-import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.haptics.vibratorHelper
-import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
-import com.android.systemui.keyguard.domain.interactor.keyguardInteractor
import com.android.systemui.kosmos.testScope
+import com.android.systemui.qs.qsTileFactory
+import com.android.systemui.statusbar.policy.keyguardStateController
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
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.Mock
+import org.mockito.junit.MockitoJUnit
+import org.mockito.junit.MockitoRule
+import org.mockito.kotlin.times
+import org.mockito.kotlin.verify
+import org.mockito.kotlin.whenever
@SmallTest
@RunWith(AndroidJUnit4::class)
@RunWithLooper(setAsMainLooper = true)
class QSLongPressEffectTest : SysuiTestCase() {
+ @Rule @JvmField val mMockitoRule: MockitoRule = MockitoJUnit.rule()
private val kosmos = testKosmos()
private val vibratorHelper = kosmos.vibratorHelper
+ private val qsTile = kosmos.qsTileFactory.createTile("Test Tile")
+ @Mock private lateinit var callback: QSLongPressEffect.Callback
private val effectDuration = 400
private val lowTickDuration = 12
@@ -54,13 +63,15 @@
lowTickDuration
vibratorHelper.primitiveDurations[VibrationEffect.Composition.PRIMITIVE_SPIN] = spinDuration
- kosmos.fakeKeyguardRepository.setKeyguardDismissible(true)
+ whenever(kosmos.keyguardStateController.isUnlocked).thenReturn(true)
longPressEffect =
QSLongPressEffect(
vibratorHelper,
- kosmos.keyguardInteractor,
+ kosmos.keyguardStateController,
)
+ longPressEffect.callback = callback
+ longPressEffect.qsTile = qsTile
}
@Test
@@ -107,28 +118,13 @@
}
@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)
+ verify(callback, times(1)).onStartAnimator()
}
@Test
@@ -179,26 +175,28 @@
}
@Test
- fun onAnimationComplete_keyguardDismissible_effectEndsWithLongPress() =
+ fun onAnimationComplete_keyguardDismissible_effectEndsWithPrepare() =
testWhileInState(QSLongPressEffect.State.RUNNING_FORWARD) {
// GIVEN that the animation completes
longPressEffect.handleAnimationComplete()
- // THEN the long-press effect completes with a LONG_PRESS
- assertEffectCompleted(QSLongPressEffect.ActionType.LONG_PRESS)
+ // THEN the long-press effect completes and the view is called to prepare
+ assertEffectCompleted()
+ verify(callback, times(1)).onPrepareForLaunch()
}
@Test
- fun onAnimationComplete_keyguardNotDismissible_effectEndsWithResetAndLongPress() =
+ fun onAnimationComplete_keyguardNotDismissible_effectEndsWithReset() =
testWhileInState(QSLongPressEffect.State.RUNNING_FORWARD) {
// GIVEN that the keyguard is not dismissible
- kosmos.fakeKeyguardRepository.setKeyguardDismissible(false)
+ whenever(kosmos.keyguardStateController.isUnlocked).thenReturn(false)
// GIVEN that the animation completes
longPressEffect.handleAnimationComplete()
- // THEN the long-press effect completes with RESET_AND_LONG_PRESS
- assertEffectCompleted(QSLongPressEffect.ActionType.RESET_AND_LONG_PRESS)
+ // THEN the long-press effect completes and the properties are called to reset
+ assertEffectCompleted()
+ verify(callback, times(1)).onResetProperties()
}
@Test
@@ -211,8 +209,7 @@
longPressEffect.handleActionDown()
// THEN the effect posts an action to cancel the animator
- val action by collectLastValue(longPressEffect.actionType)
- assertThat(action).isEqualTo(QSLongPressEffect.ActionType.CANCEL_ANIMATOR)
+ verify(callback, times(1)).onCancelAnimator()
}
@Test
@@ -238,6 +235,29 @@
assertThat(longPressEffect.state).isEqualTo(QSLongPressEffect.State.IDLE)
}
+ @Test
+ fun onTileClick_whileWaiting_withQSTile_clicks() =
+ testWhileInState(QSLongPressEffect.State.TIMEOUT_WAIT) {
+ // GIVEN that a click was detected
+ val couldClick = longPressEffect.onTileClick()
+
+ // THEN the click is successful
+ assertThat(couldClick).isTrue()
+ }
+
+ @Test
+ fun onTileClick_whileWaiting_withoutQSTile_cannotClick() =
+ testWhileInState(QSLongPressEffect.State.TIMEOUT_WAIT) {
+ // GIVEN that no QSTile has been set
+ longPressEffect.qsTile = null
+
+ // GIVEN that a click was detected
+ val couldClick = longPressEffect.onTileClick()
+
+ // THEN the click is not successful
+ assertThat(couldClick).isFalse()
+ }
+
private fun testWithScope(initialize: Boolean = true, test: suspend TestScope.() -> Unit) =
with(kosmos) {
testScope.runTest {
@@ -300,16 +320,13 @@
* Asserts that the effect completes by checking that:
* 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)
+ private fun assertEffectCompleted() {
val snapEffect = LongPressHapticBuilder.createSnapEffect()
assertThat(snapEffect).isNotNull()
assertThat(vibratorHelper.hasVibratedWithEffects(snapEffect!!)).isTrue()
assertThat(longPressEffect.state).isEqualTo(QSLongPressEffect.State.IDLE)
- assertThat(action).isEqualTo(expectedAction)
}
/**
@@ -317,10 +334,8 @@
* 1. The internal state is [QSLongPressEffect.State.RUNNING_BACKWARDS]
* 2. An action to reverse the animator is emitted
*/
- private fun TestScope.assertEffectReverses() {
- val action by collectLastValue(longPressEffect.actionType)
-
+ private fun assertEffectReverses() {
assertThat(longPressEffect.state).isEqualTo(QSLongPressEffect.State.RUNNING_BACKWARDS)
- assertThat(action).isEqualTo(QSLongPressEffect.ActionType.REVERSE_ANIMATOR)
+ verify(callback, times(1)).onReverseAnimator()
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt
index 5756bca..0f061de 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt
@@ -125,68 +125,6 @@
}
@Test
- fun dozeAmountTransitionTest_AodToFromLockscreen() =
- testScope.runTest {
- val dozeAmountSteps by collectValues(underTest.dozeAmountTransition)
-
- val steps = mutableListOf<TransitionStep>()
-
- steps.add(TransitionStep(AOD, LOCKSCREEN, 0f, STARTED))
- steps.add(TransitionStep(AOD, LOCKSCREEN, 0.5f, RUNNING))
- steps.add(TransitionStep(AOD, LOCKSCREEN, 1f, FINISHED))
- steps.add(TransitionStep(LOCKSCREEN, AOD, 0f, STARTED))
- steps.add(TransitionStep(LOCKSCREEN, AOD, 0.8f, RUNNING))
- steps.add(TransitionStep(LOCKSCREEN, AOD, 0.9f, RUNNING))
- steps.add(TransitionStep(LOCKSCREEN, AOD, 1f, FINISHED))
-
- steps.forEach {
- repository.sendTransitionStep(it)
- runCurrent()
- }
-
- assertThat(dozeAmountSteps.subList(0, 3))
- .isEqualTo(
- listOf(
- steps[0].copy(value = 1f - steps[0].value),
- steps[1].copy(value = 1f - steps[1].value),
- steps[2].copy(value = 1f - steps[2].value),
- )
- )
- assertThat(dozeAmountSteps.subList(3, 7)).isEqualTo(steps.subList(3, 7))
- }
-
- @Test
- fun dozeAmountTransitionTest_AodToFromGone() =
- testScope.runTest {
- val dozeAmountSteps by collectValues(underTest.dozeAmountTransition)
-
- val steps = mutableListOf<TransitionStep>()
-
- steps.add(TransitionStep(AOD, GONE, 0f, STARTED))
- steps.add(TransitionStep(AOD, GONE, 0.3f, RUNNING))
- steps.add(TransitionStep(AOD, GONE, 1f, FINISHED))
- steps.add(TransitionStep(GONE, AOD, 0f, STARTED))
- steps.add(TransitionStep(GONE, AOD, 0.1f, RUNNING))
- steps.add(TransitionStep(GONE, AOD, 0.3f, RUNNING))
- steps.add(TransitionStep(GONE, AOD, 1f, FINISHED))
-
- steps.forEach {
- repository.sendTransitionStep(it)
- runCurrent()
- }
-
- assertThat(dozeAmountSteps.subList(0, 3))
- .isEqualTo(
- listOf(
- steps[0].copy(value = 1f - steps[0].value),
- steps[1].copy(value = 1f - steps[1].value),
- steps[2].copy(value = 1f - steps[2].value),
- )
- )
- assertThat(dozeAmountSteps.subList(3, 7)).isEqualTo(steps.subList(3, 7))
- }
-
- @Test
fun finishedKeyguardStateTests() =
testScope.runTest {
val finishedSteps by collectValues(underTest.finishedKeyguardState)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryForegroundViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryForegroundViewModelTest.kt
index 460a1fc..b0959e4 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryForegroundViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryForegroundViewModelTest.kt
@@ -25,6 +25,7 @@
import com.android.systemui.keyguard.data.repository.fakeBiometricSettingsRepository
import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.kosmos.testScope
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
@@ -58,6 +59,62 @@
assertThat(viewModel?.tint).isEqualTo(Color.WHITE)
}
+ @Test
+ fun startsDozing_doNotShowAodVariant() =
+ testScope.runTest {
+ val viewModel by collectLastValue(underTest.viewModel)
+
+ givenUdfpsEnrolledAndEnabled()
+ kosmos.run {
+ fakeKeyguardTransitionRepository.sendTransitionSteps(
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.DOZING,
+ testScope = testScope,
+ throughTransitionState = TransitionState.STARTED,
+ )
+ }
+
+ assertThat(viewModel?.useAodVariant).isEqualTo(false)
+ }
+
+ @Test
+ fun finishedDozing_showAodVariant() =
+ testScope.runTest {
+ val viewModel by collectLastValue(underTest.viewModel)
+
+ givenUdfpsEnrolledAndEnabled()
+ kosmos.fakeKeyguardTransitionRepository.sendTransitionSteps(
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.AOD,
+ testScope = testScope,
+ throughTransitionState = TransitionState.FINISHED,
+ )
+
+ assertThat(viewModel?.useAodVariant).isEqualTo(true)
+ }
+
+ @Test
+ fun startTransitionToLockscreenFromDozing_doNotShowAodVariant() =
+ testScope.runTest {
+ val viewModel by collectLastValue(underTest.viewModel)
+
+ givenUdfpsEnrolledAndEnabled()
+ kosmos.fakeKeyguardTransitionRepository.sendTransitionSteps(
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.DOZING,
+ testScope = testScope,
+ throughTransitionState = TransitionState.FINISHED,
+ )
+ kosmos.fakeKeyguardTransitionRepository.sendTransitionSteps(
+ from = KeyguardState.DOZING,
+ to = KeyguardState.LOCKSCREEN,
+ testScope = testScope,
+ throughTransitionState = TransitionState.RUNNING,
+ )
+
+ assertThat(viewModel?.useAodVariant).isEqualTo(false)
+ }
+
private fun givenUdfpsEnrolledAndEnabled() {
kosmos.fakeFingerprintPropertyRepository.supportsUdfps()
kosmos.fakeBiometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(true)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModelTest.kt
index 68fbd1c..3f93401 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModelTest.kt
@@ -227,11 +227,11 @@
assertThat(accessibilityDelegateHint)
.isEqualTo(DeviceEntryIconView.AccessibilityHintType.AUTHENTICATE)
- // non-interactive lock icon
+ // interactive lock icon for non udfps as well so that user can navigate to bouncer
fingerprintPropertyRepository.supportsRearFps()
assertThat(accessibilityDelegateHint)
- .isEqualTo(DeviceEntryIconView.AccessibilityHintType.NONE)
+ .isEqualTo(DeviceEntryIconView.AccessibilityHintType.AUTHENTICATE)
}
@Test
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt
index 49df345..194f362 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt
@@ -39,7 +39,9 @@
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.kosmos.testScope
+import com.android.systemui.scene.data.repository.Idle
import com.android.systemui.scene.data.repository.sceneContainerRepository
+import com.android.systemui.scene.data.repository.setSceneTransition
import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.shade.shadeTestUtil
@@ -290,6 +292,7 @@
testScope,
)
+ kosmos.setSceneTransition(Idle(Scenes.Gone))
// Make sure the value hasn't changed since we're GONE
keyguardRepository.topClippingBounds.value = 5
assertThat(topClippingBounds).isEqualTo(1000)
@@ -518,11 +521,14 @@
to = KeyguardState.GONE,
testScope = testScope,
)
+ kosmos.setSceneTransition(Idle(Scenes.Gone))
assertThat(alpha).isEqualTo(0f)
- // Try pulling down shade and ensure the value doesn't change
- shadeTestUtil.setQsExpansion(0.5f)
- assertThat(alpha).isEqualTo(0f)
+ if (!SceneContainerFlag.isEnabled) {
+ // Try pulling down shade and ensure the value doesn't change
+ shadeTestUtil.setQsExpansion(0.5f)
+ assertThat(alpha).isEqualTo(0f)
+ }
}
@Test
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt
index f46ca00..61d8216 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt
@@ -50,6 +50,7 @@
import com.google.common.truth.Truth.assertThat
import kotlin.math.pow
import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.test.runTest
import org.junit.BeforeClass
import org.junit.Test
@@ -205,8 +206,13 @@
pointerCount = if (downWithTwoPointers) 2 else 1,
)
)
-
- assertThat(downDestination?.toScene)
+ val downScene by
+ collectLastValue(
+ downDestination?.let {
+ kosmos.sceneInteractor.resolveSceneFamily(downDestination.toScene)
+ } ?: flowOf(null)
+ )
+ assertThat(downScene)
.isEqualTo(
expectedDownDestination(
downFromEdge = downFromEdge,
@@ -223,7 +229,14 @@
)
)
- assertThat(destinationScenes?.get(Swipe(SwipeDirection.Up))?.toScene)
+ val upScene by
+ collectLastValue(
+ destinationScenes?.get(Swipe(SwipeDirection.Up))?.toScene?.let { scene ->
+ kosmos.sceneInteractor.resolveSceneFamily(scene)
+ } ?: flowOf(null)
+ )
+
+ assertThat(upScene)
.isEqualTo(
expectedUpDestination(
canSwipeToEnter = canSwipeToEnter,
@@ -231,7 +244,14 @@
)
)
- assertThat(destinationScenes?.get(Swipe(SwipeDirection.Left))?.toScene)
+ val leftScene by
+ collectLastValue(
+ destinationScenes?.get(Swipe(SwipeDirection.Left))?.toScene?.let { scene ->
+ kosmos.sceneInteractor.resolveSceneFamily(scene)
+ } ?: flowOf(null)
+ )
+
+ assertThat(leftScene)
.isEqualTo(
expectedLeftDestination(
isCommunalAvailable = isCommunalAvailable,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/data/repository/MediaFilterRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/data/repository/MediaFilterRepositoryTest.kt
index 7a37a9e..73e6506 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/data/repository/MediaFilterRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/data/repository/MediaFilterRepositoryTest.kt
@@ -56,11 +56,15 @@
underTest.addSelectedUserMediaEntry(userMedia)
assertThat(selectedUserEntries?.get(instanceId)).isEqualTo(userMedia)
+ assertThat(underTest.hasActiveMedia()).isTrue()
+ assertThat(underTest.hasAnyMedia()).isTrue()
underTest.addSelectedUserMediaEntry(userMedia.copy(active = false))
assertThat(selectedUserEntries?.get(instanceId)).isNotEqualTo(userMedia)
assertThat(selectedUserEntries?.get(instanceId)?.active).isFalse()
+ assertThat(underTest.hasActiveMedia()).isFalse()
+ assertThat(underTest.hasAnyMedia()).isTrue()
}
@Test
@@ -74,8 +78,12 @@
underTest.addSelectedUserMediaEntry(userMedia)
assertThat(selectedUserEntries?.get(instanceId)).isEqualTo(userMedia)
+ assertThat(underTest.hasActiveMedia()).isTrue()
+ assertThat(underTest.hasAnyMedia()).isTrue()
assertThat(underTest.removeSelectedUserMediaEntry(instanceId, userMedia)).isTrue()
+ assertThat(underTest.hasActiveMedia()).isFalse()
+ assertThat(underTest.hasAnyMedia()).isFalse()
}
@Test
@@ -145,6 +153,7 @@
assertThat(smartspaceMediaData).isNotEqualTo(mediaRecommendation)
assertThat(smartspaceMediaData?.isActive).isFalse()
+ assertThat(underTest.isRecommendationActive()).isFalse()
}
@Test
@@ -349,6 +358,14 @@
.inOrder()
}
+ @Test
+ fun hasAnyMedia_noMediaSet_returnsFalse() =
+ testScope.runTest { assertThat(underTest.hasAnyMedia()).isFalse() }
+
+ @Test
+ fun hasActiveMedia_noMediaSet_returnsFalse() =
+ testScope.runTest { assertThat(underTest.hasActiveMedia()).isFalse() }
+
private fun createMediaData(
app: String,
playing: Boolean,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/domain/interactor/MediaCarouselInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/domain/interactor/MediaCarouselInteractorTest.kt
index 39dbc7e..c62195f 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/domain/interactor/MediaCarouselInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/domain/interactor/MediaCarouselInteractorTest.kt
@@ -76,22 +76,20 @@
testScope.runTest {
val hasActiveMediaOrRecommendation by
collectLastValue(underTest.hasActiveMediaOrRecommendation)
- val hasActiveMedia by collectLastValue(underTest.hasActiveMedia)
- val hasAnyMedia by collectLastValue(underTest.hasAnyMedia)
val userMedia = MediaData(active = true)
mediaFilterRepository.addSelectedUserMediaEntry(userMedia)
assertThat(hasActiveMediaOrRecommendation).isTrue()
- assertThat(hasActiveMedia).isTrue()
- assertThat(hasAnyMedia).isTrue()
+ assertThat(underTest.hasActiveMedia()).isTrue()
+ assertThat(underTest.hasAnyMedia()).isTrue()
mediaFilterRepository.addSelectedUserMediaEntry(userMedia.copy(active = false))
assertThat(hasActiveMediaOrRecommendation).isFalse()
- assertThat(hasActiveMedia).isFalse()
- assertThat(hasAnyMedia).isTrue()
+ assertThat(underTest.hasActiveMedia()).isFalse()
+ assertThat(underTest.hasAnyMedia()).isTrue()
}
@Test
@@ -99,8 +97,6 @@
testScope.runTest {
val hasActiveMediaOrRecommendation by
collectLastValue(underTest.hasActiveMediaOrRecommendation)
- val hasActiveMedia by collectLastValue(underTest.hasActiveMedia)
- val hasAnyMedia by collectLastValue(underTest.hasAnyMedia)
val userMedia = MediaData(active = false)
val instanceId = userMedia.instanceId
@@ -109,8 +105,8 @@
mediaFilterRepository.addMediaDataLoadingState(MediaDataLoadingModel.Loaded(instanceId))
assertThat(hasActiveMediaOrRecommendation).isFalse()
- assertThat(hasActiveMedia).isFalse()
- assertThat(hasAnyMedia).isTrue()
+ assertThat(underTest.hasActiveMedia()).isFalse()
+ assertThat(underTest.hasAnyMedia()).isTrue()
assertThat(mediaFilterRepository.removeSelectedUserMediaEntry(instanceId, userMedia))
.isTrue()
@@ -119,8 +115,8 @@
)
assertThat(hasActiveMediaOrRecommendation).isFalse()
- assertThat(hasActiveMedia).isFalse()
- assertThat(hasAnyMedia).isFalse()
+ assertThat(underTest.hasActiveMedia()).isFalse()
+ assertThat(underTest.hasAnyMedia()).isFalse()
}
@Test
@@ -147,6 +143,7 @@
mediaFilterRepository.addSelectedUserMediaEntry(userMedia)
mediaFilterRepository.addMediaDataLoadingState(mediaLoadingModel)
+ mediaFilterRepository.setOrderedMedia()
assertThat(hasActiveMediaOrRecommendation).isTrue()
assertThat(hasAnyMediaOrRecommendation).isTrue()
@@ -202,7 +199,7 @@
@Test
fun hasAnyMedia_noMediaSet_returnsFalse() =
- testScope.runTest { assertThat(underTest.hasAnyMedia.value).isFalse() }
+ testScope.runTest { assertThat(underTest.hasAnyMedia()).isFalse() }
@Test
fun hasAnyMediaOrRecommendation_noMediaSet_returnsFalse() =
@@ -210,7 +207,7 @@
@Test
fun hasActiveMedia_noMediaSet_returnsFalse() =
- testScope.runTest { assertThat(underTest.hasActiveMedia.value).isFalse() }
+ testScope.runTest { assertThat(underTest.hasActiveMedia()).isFalse() }
@Test
fun hasActiveMediaOrRecommendation_nothingSet_returnsFalse() =
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeSceneViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeSceneViewModelTest.kt
index 6b1794e2..cb4e2d3 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeSceneViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeSceneViewModelTest.kt
@@ -30,8 +30,8 @@
import com.android.systemui.keyguard.data.repository.fakeDeviceEntryFingerprintAuthRepository
import com.android.systemui.keyguard.shared.model.SuccessFingerprintAuthenticationStatus
import com.android.systemui.kosmos.testScope
-import com.android.systemui.scene.domain.interactor.homeSceneFamilyResolver
import com.android.systemui.scene.domain.interactor.sceneInteractor
+import com.android.systemui.scene.domain.resolver.homeSceneFamilyResolver
import com.android.systemui.scene.shared.model.SceneFamilies
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.shade.ui.viewmodel.notificationsShadeSceneViewModel
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 7ee20e5..5b6fea5 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
@@ -41,10 +41,10 @@
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.homeSceneFamilyResolver
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.domain.resolver.homeSceneFamilyResolver
import com.android.systemui.scene.shared.model.SceneFamilies
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.settings.brightness.ui.viewmodel.brightnessMirrorViewModel
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeSceneViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeSceneViewModelTest.kt
index f28ddeb..ac67ac8 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeSceneViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeSceneViewModelTest.kt
@@ -30,8 +30,8 @@
import com.android.systemui.keyguard.data.repository.fakeDeviceEntryFingerprintAuthRepository
import com.android.systemui.keyguard.shared.model.SuccessFingerprintAuthenticationStatus
import com.android.systemui.kosmos.testScope
-import com.android.systemui.scene.domain.interactor.homeSceneFamilyResolver
import com.android.systemui.scene.domain.interactor.sceneInteractor
+import com.android.systemui.scene.domain.resolver.homeSceneFamilyResolver
import com.android.systemui.scene.shared.model.SceneFamilies
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.shade.ui.viewmodel.quickSettingsShadeSceneViewModel
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt
index f8a62cb..4d5d22c 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt
@@ -58,9 +58,9 @@
import com.android.systemui.qs.footerActionsController
import com.android.systemui.qs.footerActionsViewModelFactory
import com.android.systemui.qs.ui.adapter.FakeQSSceneAdapter
-import com.android.systemui.scene.domain.interactor.homeSceneFamilyResolver
import com.android.systemui.scene.domain.interactor.sceneContainerStartable
import com.android.systemui.scene.domain.interactor.sceneInteractor
+import com.android.systemui.scene.domain.resolver.homeSceneFamilyResolver
import com.android.systemui.scene.shared.model.SceneFamilies
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.scene.shared.model.fakeSceneDataSource
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 881ce41..ec7150b 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
@@ -21,16 +21,20 @@
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.compose.animation.scene.ObservableTransitionState
+import com.android.compose.animation.scene.SceneKey
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.flags.EnableSceneContainer
import com.android.systemui.keyguard.data.repository.fakeDeviceEntryFingerprintAuthRepository
import com.android.systemui.keyguard.shared.model.SuccessFingerprintAuthenticationStatus
import com.android.systemui.kosmos.testScope
+import com.android.systemui.scene.data.repository.Idle
+import com.android.systemui.scene.data.repository.Transition
import com.android.systemui.scene.data.repository.sceneContainerRepository
+import com.android.systemui.scene.data.repository.setSceneTransition
+import com.android.systemui.scene.domain.resolver.homeSceneFamilyResolver
import com.android.systemui.scene.sceneContainerConfig
import com.android.systemui.scene.sceneKeys
-import com.android.systemui.scene.shared.model.SceneContainerConfig
import com.android.systemui.scene.shared.model.SceneFamilies
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.scene.shared.model.fakeSceneDataSource
@@ -38,6 +42,7 @@
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.toList
import kotlinx.coroutines.test.runCurrent
@@ -54,48 +59,27 @@
private val testScope = kosmos.testScope
private val fakeSceneDataSource = kosmos.fakeSceneDataSource
- private lateinit var underTest: SceneInteractor
+ private val underTest = kosmos.sceneInteractor
@Test
fun allSceneKeys() {
- underTest = kosmos.sceneInteractor
assertThat(underTest.allSceneKeys()).isEqualTo(kosmos.sceneKeys)
}
@Test
fun changeScene_toUnknownScene_doesNothing() =
testScope.runTest {
- val sceneKeys =
- listOf(
- Scenes.QuickSettings,
- Scenes.Shade,
- Scenes.Lockscreen,
- Scenes.Gone,
- Scenes.Communal,
- )
- val navigationDistances =
- mapOf(
- Scenes.Gone to 0,
- Scenes.Lockscreen to 0,
- Scenes.Communal to 1,
- Scenes.Shade to 2,
- Scenes.QuickSettings to 3,
- )
- kosmos.sceneContainerConfig =
- SceneContainerConfig(sceneKeys, Scenes.Lockscreen, navigationDistances)
- underTest = kosmos.sceneInteractor
val currentScene by collectLastValue(underTest.currentScene)
+ val unknownScene = SceneKey("UNKNOWN")
val previousScene = currentScene
- assertThat(previousScene).isNotEqualTo(Scenes.Bouncer)
- underTest.changeScene(Scenes.Bouncer, "reason")
+ assertThat(previousScene).isNotEqualTo(unknownScene)
+ underTest.changeScene(unknownScene, "reason")
assertThat(currentScene).isEqualTo(previousScene)
}
@Test
fun changeScene() =
testScope.runTest {
- underTest = kosmos.sceneInteractor
-
val currentScene by collectLastValue(underTest.currentScene)
assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
@@ -106,8 +90,6 @@
@Test
fun changeScene_toGoneWhenUnl_doesNotThrow() =
testScope.runTest {
- underTest = kosmos.sceneInteractor
-
val currentScene by collectLastValue(underTest.currentScene)
assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
@@ -122,15 +104,11 @@
@Test(expected = IllegalStateException::class)
fun changeScene_toGoneWhenStillLocked_throws() =
- testScope.runTest {
- underTest = kosmos.sceneInteractor
- underTest.changeScene(Scenes.Gone, "reason")
- }
+ testScope.runTest { underTest.changeScene(Scenes.Gone, "reason") }
@Test
fun changeScene_toGoneWhenTransitionToLockedFromGone() =
testScope.runTest {
- underTest = kosmos.sceneInteractor
val currentScene by collectLastValue(underTest.currentScene)
val transitionTo by collectLastValue(underTest.transitioningTo)
kosmos.sceneContainerRepository.setTransitionState(
@@ -155,7 +133,6 @@
@Test
fun changeScene_toHomeSceneFamily() =
testScope.runTest {
- underTest = kosmos.sceneInteractor
val currentScene by collectLastValue(underTest.currentScene)
underTest.changeScene(SceneFamilies.Home, "reason")
@@ -167,37 +144,17 @@
@Test
fun snapToScene_toUnknownScene_doesNothing() =
testScope.runTest {
- val sceneKeys =
- listOf(
- Scenes.QuickSettings,
- Scenes.Shade,
- Scenes.Lockscreen,
- Scenes.Gone,
- Scenes.Communal,
- )
- val navigationDistances =
- mapOf(
- Scenes.Gone to 0,
- Scenes.Lockscreen to 0,
- Scenes.Communal to 1,
- Scenes.Shade to 2,
- Scenes.QuickSettings to 3,
- )
- kosmos.sceneContainerConfig =
- SceneContainerConfig(sceneKeys, Scenes.Lockscreen, navigationDistances)
- underTest = kosmos.sceneInteractor
val currentScene by collectLastValue(underTest.currentScene)
val previousScene = currentScene
- assertThat(previousScene).isNotEqualTo(Scenes.Bouncer)
- underTest.snapToScene(Scenes.Bouncer, "reason")
+ val unknownScene = SceneKey("UNKNOWN")
+ assertThat(previousScene).isNotEqualTo(unknownScene)
+ underTest.snapToScene(unknownScene, "reason")
assertThat(currentScene).isEqualTo(previousScene)
}
@Test
fun snapToScene() =
testScope.runTest {
- underTest = kosmos.sceneInteractor
-
val currentScene by collectLastValue(underTest.currentScene)
assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
@@ -208,8 +165,6 @@
@Test
fun snapToScene_toGoneWhenUnl_doesNotThrow() =
testScope.runTest {
- underTest = kosmos.sceneInteractor
-
val currentScene by collectLastValue(underTest.currentScene)
assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
@@ -224,15 +179,11 @@
@Test(expected = IllegalStateException::class)
fun snapToScene_toGoneWhenStillLocked_throws() =
- testScope.runTest {
- underTest = kosmos.sceneInteractor
- underTest.snapToScene(Scenes.Gone, "reason")
- }
+ testScope.runTest { underTest.snapToScene(Scenes.Gone, "reason") }
@Test
fun snapToScene_toHomeSceneFamily() =
testScope.runTest {
- underTest = kosmos.sceneInteractor
val currentScene by collectLastValue(underTest.currentScene)
underTest.snapToScene(SceneFamilies.Home, "reason")
@@ -244,7 +195,6 @@
@Test
fun sceneChanged_inDataSource() =
testScope.runTest {
- underTest = kosmos.sceneInteractor
val currentScene by collectLastValue(underTest.currentScene)
assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
@@ -256,14 +206,14 @@
@Test
fun transitionState() =
testScope.runTest {
- underTest = kosmos.sceneInteractor
- val underTest = kosmos.sceneContainerRepository
+ val sceneContainerRepository = kosmos.sceneContainerRepository
val transitionState =
MutableStateFlow<ObservableTransitionState>(
ObservableTransitionState.Idle(Scenes.Lockscreen)
)
- underTest.setTransitionState(transitionState)
- val reflectedTransitionState by collectLastValue(underTest.transitionState)
+ sceneContainerRepository.setTransitionState(transitionState)
+ val reflectedTransitionState by
+ collectLastValue(sceneContainerRepository.transitionState)
assertThat(reflectedTransitionState).isEqualTo(transitionState.value)
val progress = MutableStateFlow(1f)
@@ -284,7 +234,7 @@
progress.value = 0.9f
assertThat(reflectedTransitionState).isEqualTo(transitionState.value)
- underTest.setTransitionState(null)
+ sceneContainerRepository.setTransitionState(null)
assertThat(reflectedTransitionState)
.isEqualTo(
ObservableTransitionState.Idle(kosmos.sceneContainerConfig.initialSceneKey)
@@ -294,7 +244,6 @@
@Test
fun transitioningTo() =
testScope.runTest {
- underTest = kosmos.sceneInteractor
val transitionState =
MutableStateFlow<ObservableTransitionState>(
ObservableTransitionState.Idle(underTest.currentScene.value)
@@ -332,7 +281,6 @@
@Test
fun isTransitionUserInputOngoing_idle_false() =
testScope.runTest {
- underTest = kosmos.sceneInteractor
val transitionState =
MutableStateFlow<ObservableTransitionState>(
ObservableTransitionState.Idle(Scenes.Shade)
@@ -347,7 +295,6 @@
@Test
fun isTransitionUserInputOngoing_transition_true() =
testScope.runTest {
- underTest = kosmos.sceneInteractor
val transitionState =
MutableStateFlow<ObservableTransitionState>(
ObservableTransitionState.Transition(
@@ -369,7 +316,6 @@
@Test
fun isTransitionUserInputOngoing_updateMidTransition_false() =
testScope.runTest {
- underTest = kosmos.sceneInteractor
val transitionState =
MutableStateFlow<ObservableTransitionState>(
ObservableTransitionState.Transition(
@@ -403,7 +349,6 @@
@Test
fun isTransitionUserInputOngoing_updateOnIdle_false() =
testScope.runTest {
- underTest = kosmos.sceneInteractor
val transitionState =
MutableStateFlow<ObservableTransitionState>(
ObservableTransitionState.Transition(
@@ -429,7 +374,6 @@
@Test
fun isVisible() =
testScope.runTest {
- underTest = kosmos.sceneInteractor
val isVisible by collectLastValue(underTest.isVisible)
assertThat(isVisible).isTrue()
@@ -443,7 +387,6 @@
@Test
fun isVisible_duringRemoteUserInteraction_forcedVisible() =
testScope.runTest {
- underTest = kosmos.sceneInteractor
underTest.setVisible(false, "reason")
val isVisible by collectLastValue(underTest.isVisible)
assertThat(isVisible).isFalse()
@@ -458,16 +401,53 @@
@Test
fun resolveSceneFamily_home() =
testScope.runTest {
- underTest = kosmos.sceneInteractor
- assertThat(underTest.resolveSceneFamily(SceneFamilies.Home))
- .isEqualTo(kosmos.homeSceneFamilyResolver.resolvedScene)
+ assertThat(underTest.resolveSceneFamily(SceneFamilies.Home).first())
+ .isEqualTo(kosmos.homeSceneFamilyResolver.resolvedScene.value)
}
@Test
fun resolveSceneFamily_nonFamily() =
testScope.runTest {
- underTest = kosmos.sceneInteractor
val resolved = underTest.resolveSceneFamily(Scenes.Gone).toList()
assertThat(resolved).containsExactly(Scenes.Gone).inOrder()
}
+
+ @Test
+ fun transitionValue_test_idle() =
+ testScope.runTest {
+ val transitionValue by collectLastValue(underTest.transitionProgress(Scenes.Gone))
+
+ kosmos.setSceneTransition(Idle(Scenes.Gone))
+ assertThat(transitionValue).isEqualTo(1f)
+
+ kosmos.setSceneTransition(Idle(Scenes.Lockscreen))
+ assertThat(transitionValue).isEqualTo(0f)
+ }
+
+ @Test
+ fun transitionValue_test_transitions() =
+ testScope.runTest {
+ val transitionValue by collectLastValue(underTest.transitionProgress(Scenes.Gone))
+ val progress = MutableStateFlow(0f)
+
+ kosmos.setSceneTransition(
+ Transition(from = Scenes.Lockscreen, to = Scenes.Gone, progress = progress)
+ )
+ assertThat(transitionValue).isEqualTo(0f)
+
+ progress.value = 0.4f
+ assertThat(transitionValue).isEqualTo(0.4f)
+
+ kosmos.setSceneTransition(
+ Transition(from = Scenes.Gone, to = Scenes.Lockscreen, progress = progress)
+ )
+ progress.value = 0.7f
+ assertThat(transitionValue).isEqualTo(0.3f)
+
+ kosmos.setSceneTransition(
+ Transition(from = Scenes.Lockscreen, to = Scenes.Shade, progress = progress)
+ )
+ progress.value = 0.9f
+ assertThat(transitionValue).isEqualTo(0f)
+ }
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeBackActionInteractorImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeBackActionInteractorImplTest.kt
index 3a5ff00..fa4da42 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeBackActionInteractorImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeBackActionInteractorImplTest.kt
@@ -29,8 +29,8 @@
import com.android.systemui.keyguard.data.repository.deviceEntryFingerprintAuthRepository
import com.android.systemui.keyguard.shared.model.SuccessFingerprintAuthenticationStatus
import com.android.systemui.kosmos.testScope
-import com.android.systemui.scene.domain.interactor.homeSceneFamilyResolver
import com.android.systemui.scene.domain.interactor.sceneInteractor
+import com.android.systemui.scene.domain.resolver.homeSceneFamilyResolver
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.shared.recents.utilities.Utilities
import com.android.systemui.testKosmos
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt
index f88d102..c53cdf8 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt
@@ -19,6 +19,8 @@
import android.testing.TestableLooper
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
+import com.android.compose.animation.scene.ObservableTransitionState
+import com.android.compose.animation.scene.SceneKey
import com.android.compose.animation.scene.Swipe
import com.android.compose.animation.scene.SwipeDirection
import com.android.systemui.SysuiTestCase
@@ -27,6 +29,7 @@
import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository
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.keyguard.data.repository.fakeDeviceEntryFingerprintAuthRepository
import com.android.systemui.keyguard.shared.model.SuccessFingerprintAuthenticationStatus
@@ -39,8 +42,8 @@
import com.android.systemui.qs.footerActionsViewModelFactory
import com.android.systemui.qs.ui.adapter.FakeQSSceneAdapter
import com.android.systemui.res.R
-import com.android.systemui.scene.domain.interactor.homeSceneFamilyResolver
import com.android.systemui.scene.domain.interactor.sceneInteractor
+import com.android.systemui.scene.domain.resolver.homeSceneFamilyResolver
import com.android.systemui.scene.shared.model.SceneFamilies
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.scene.shared.model.TransitionKeys.ToSplitShade
@@ -57,7 +60,9 @@
import com.google.common.truth.Truth.assertThat
import java.util.Locale
import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
@@ -126,9 +131,7 @@
kosmos.fakeAuthenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin
)
- kosmos.fakeDeviceEntryFingerprintAuthRepository.setAuthenticationStatus(
- SuccessFingerprintAuthenticationStatus(0, true)
- )
+ setDeviceEntered(true)
assertThat(destinationScenes?.get(Swipe(SwipeDirection.Up))?.toScene)
.isEqualTo(SceneFamilies.Home)
@@ -196,9 +199,7 @@
kosmos.fakeAuthenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin
)
- kosmos.fakeDeviceEntryFingerprintAuthRepository.setAuthenticationStatus(
- SuccessFingerprintAuthenticationStatus(0, true)
- )
+ setDeviceEntered(true)
runCurrent()
assertThat(isClickable).isFalse()
@@ -345,6 +346,32 @@
return maxTranslation
}
+ private fun TestScope.setDeviceEntered(isEntered: Boolean) {
+ if (isEntered) {
+ // Unlock the device marking the device has entered.
+ kosmos.fakeDeviceEntryFingerprintAuthRepository.setAuthenticationStatus(
+ SuccessFingerprintAuthenticationStatus(0, true)
+ )
+ runCurrent()
+ }
+ setScene(
+ if (isEntered) {
+ Scenes.Gone
+ } else {
+ Scenes.Lockscreen
+ }
+ )
+ assertThat(kosmos.deviceEntryInteractor.isDeviceEntered.value).isEqualTo(isEntered)
+ }
+
+ private fun TestScope.setScene(key: SceneKey) {
+ sceneInteractor.changeScene(key, "test")
+ sceneInteractor.setTransitionState(
+ MutableStateFlow<ObservableTransitionState>(ObservableTransitionState.Idle(key))
+ )
+ runCurrent()
+ }
+
private data class Translations(
val start: Float,
val end: Float,
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 88bef91..206b39c 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
@@ -627,7 +627,7 @@
hum.onEntryAdded(entryToPin);
assertEquals(2, mUiEventLoggerFake.numLogs());
- assertEquals(AvalancheController.ThrottleEvent.SHOWN.getId(),
+ assertEquals(AvalancheController.ThrottleEvent.AVALANCHE_THROTTLING_HUN_SHOWN.getId(),
mUiEventLoggerFake.eventId(0));
assertEquals(BaseHeadsUpManager.NotificationPeekEvent.NOTIFICATION_PEEK.getId(),
mUiEventLoggerFake.eventId(1));
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/domain/interactor/AudioOutputInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/domain/interactor/AudioOutputInteractorTest.kt
index 10a4eb7..7385a47 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/domain/interactor/AudioOutputInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/domain/interactor/AudioOutputInteractorTest.kt
@@ -71,6 +71,7 @@
addOverride(R.drawable.ic_headphone, testIcon)
addOverride(R.drawable.ic_smartphone, testIcon)
addOverride(R.drawable.ic_media_speaker_device, testIcon)
+ addOverride(R.drawable.ic_media_tablet, testIcon)
addOverride(com.android.internal.R.drawable.ic_bt_hearing_aid, testIcon)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaOutputComponentInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaOutputComponentInteractorTest.kt
index 8921a23..0f56d0b 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaOutputComponentInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaOutputComponentInteractorTest.kt
@@ -65,6 +65,7 @@
with(context.orCreateTestableResources) {
addOverride(R.drawable.ic_smartphone, testIcon)
+ addOverride(R.drawable.ic_media_tablet, testIcon)
addOverride(R.string.media_transfer_this_device_name_tv, builtInDeviceName)
addOverride(R.string.media_transfer_this_device_name_tablet, builtInDeviceName)
diff --git a/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java b/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java
index 83658d3..9ad4012 100644
--- a/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java
+++ b/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java
@@ -134,6 +134,12 @@
default void setScreenOn(boolean screenOn) {}
/**
+ * Sets a delegate to handle clock event registration. Should be called immediately after
+ * the view is created.
+ */
+ default void setTimeChangedDelegate(TimeChangedDelegate delegate) {}
+
+ /**
* Set if dozing is true or false
*/
default void setDozing(boolean dozing) {}
@@ -228,4 +234,13 @@
/** Start the PendingIntent */
void startPendingIntent(View v, PendingIntent pi, boolean showOnLockscreen);
}
+
+ /** Interface for delegating time updates */
+ interface TimeChangedDelegate {
+ /** Register the callback to be called when time is updated **/
+ void register(Runnable callback);
+
+ /** Unegister the callback **/
+ void unregister();
+ }
}
diff --git a/packages/SystemUI/res/drawable/ic_bt_le_audio_sharing_18dp.xml b/packages/SystemUI/res/drawable/ic_bt_le_audio_sharing_18dp.xml
new file mode 100644
index 0000000..dd3d9e3
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_bt_le_audio_sharing_18dp.xml
@@ -0,0 +1,22 @@
+<?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.
+ -->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
+ <item
+ android:drawable="@drawable/ic_bt_le_audio_sharing"
+ android:width="18dp"
+ android:height="18dp" />
+</layer-list>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout-land/volume_dialog.xml b/packages/SystemUI/res/layout-land/volume_dialog.xml
index 5ce2601..08edf59 100644
--- a/packages/SystemUI/res/layout-land/volume_dialog.xml
+++ b/packages/SystemUI/res/layout-land/volume_dialog.xml
@@ -13,9 +13,7 @@
~ See the License for the specific language governing permissions and
~ limitations under the License
-->
-<FrameLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:sysui="http://schemas.android.com/apk/res-auto"
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:id="@+id/volume_dialog_container"
android:layout_width="wrap_content"
@@ -97,16 +95,18 @@
android:paddingLeft="@dimen/volume_dialog_ringer_rows_padding"
android:paddingBottom="@dimen/volume_dialog_ringer_rows_padding"
android:paddingRight="@dimen/volume_dialog_ringer_rows_padding">
+
<com.android.keyguard.AlphaOptimizedImageButton
android:id="@+id/settings"
- android:src="@drawable/horizontal_ellipsis"
android:layout_width="@dimen/volume_dialog_tap_target_size"
android:layout_height="@dimen/volume_dialog_tap_target_size"
android:layout_gravity="center"
- android:contentDescription="@string/accessibility_volume_settings"
android:background="@drawable/ripple_drawable_20dp"
- android:tint="?androidprv:attr/colorAccent"
- android:soundEffectsEnabled="false" />
+ android:contentDescription="@string/accessibility_volume_settings"
+ android:scaleType="centerInside"
+ android:soundEffectsEnabled="false"
+ android:src="@drawable/horizontal_ellipsis"
+ android:tint="?androidprv:attr/colorAccent" />
</FrameLayout>
</LinearLayout>
diff --git a/packages/SystemUI/res/layout/dream_overlay_status_bar_view.xml b/packages/SystemUI/res/layout/ambient_status_bar_view.xml
similarity index 97%
rename from packages/SystemUI/res/layout/dream_overlay_status_bar_view.xml
rename to packages/SystemUI/res/layout/ambient_status_bar_view.xml
index ec2edb5..7d765ce 100644
--- a/packages/SystemUI/res/layout/dream_overlay_status_bar_view.xml
+++ b/packages/SystemUI/res/layout/ambient_status_bar_view.xml
@@ -14,7 +14,7 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-<com.android.systemui.dreams.DreamOverlayStatusBarView
+<com.android.systemui.ambient.statusbar.ui.AmbientStatusBarView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/dream_overlay_status_bar"
@@ -118,4 +118,4 @@
android:contentDescription="@string/assistant_attention_content_description" />
</LinearLayout>
-</com.android.systemui.dreams.DreamOverlayStatusBarView>
+</com.android.systemui.ambient.statusbar.ui.AmbientStatusBarView>
diff --git a/packages/SystemUI/res/layout/bluetooth_tile_dialog.xml b/packages/SystemUI/res/layout/bluetooth_tile_dialog.xml
index a598007..27b8006 100644
--- a/packages/SystemUI/res/layout/bluetooth_tile_dialog.xml
+++ b/packages/SystemUI/res/layout/bluetooth_tile_dialog.xml
@@ -268,6 +268,12 @@
android:ellipsize="end"
android:maxLines="1"
android:text="@string/quick_settings_bluetooth_audio_sharing_button"
+ android:drawableStart="@drawable/ic_bt_le_audio_sharing_18dp"
+ android:drawablePadding="10dp"
+ android:drawableTint="?android:attr/textColorPrimary"
+ app:layout_constrainedWidth="true"
+ app:layout_constraintHorizontal_bias="0"
+ app:layout_constraintEnd_toStartOf="@+id/done_button"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@+id/barrier"
diff --git a/packages/SystemUI/res/layout/dream_overlay_container.xml b/packages/SystemUI/res/layout/dream_overlay_container.xml
index 4234fca5..dcd3fa6 100644
--- a/packages/SystemUI/res/layout/dream_overlay_container.xml
+++ b/packages/SystemUI/res/layout/dream_overlay_container.xml
@@ -44,5 +44,5 @@
app:layout_constraintBottom_toBottomOf="parent"
/>
- <include layout="@layout/dream_overlay_status_bar_view" />
+ <include layout="@layout/ambient_status_bar_view" />
</com.android.systemui.dreams.DreamOverlayContainerView>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/hearing_devices_preset_dropdown_item.xml b/packages/SystemUI/res/layout/hearing_devices_preset_dropdown_item.xml
index 1d9307b..17c0222 100644
--- a/packages/SystemUI/res/layout/hearing_devices_preset_dropdown_item.xml
+++ b/packages/SystemUI/res/layout/hearing_devices_preset_dropdown_item.xml
@@ -22,4 +22,5 @@
android:minHeight="@dimen/hearing_devices_preset_spinner_height"
android:paddingStart="@dimen/hearing_devices_preset_spinner_text_padding_start"
android:gravity="center_vertical"
+ android:textDirection="locale"
android:ellipsize="end" />
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/hearing_devices_preset_spinner_selected.xml b/packages/SystemUI/res/layout/hearing_devices_preset_spinner_selected.xml
index 77172ca..d512e7c 100644
--- a/packages/SystemUI/res/layout/hearing_devices_preset_spinner_selected.xml
+++ b/packages/SystemUI/res/layout/hearing_devices_preset_spinner_selected.xml
@@ -32,6 +32,7 @@
android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
android:textSize="14sp"
android:gravity="center_vertical"
+ android:textDirection="locale"
android:layout_weight="1" />
<TextView
android:id="@+id/hearing_devices_preset_option_text"
@@ -42,5 +43,6 @@
android:gravity="center_vertical"
android:ellipsize="end"
android:maxLines="1"
+ android:textDirection="locale"
android:layout_weight="1" />
</LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index c2ca4da..0017db6 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -699,9 +699,9 @@
<!-- QuickSettings: Bluetooth auto on info text when enabled [CHAR LIMIT=NONE]-->
<string name="turn_on_bluetooth_auto_info_enabled">Bluetooth will turn on tomorrow morning</string>
<!-- QuickSettings: Bluetooth dialog audio sharing button text [CHAR LIMIT=50]-->
- <string name="quick_settings_bluetooth_audio_sharing_button">Audio Sharing</string>
+ <string name="quick_settings_bluetooth_audio_sharing_button">Share audio</string>
<!-- QuickSettings: Bluetooth dialog audio sharing button text when sharing audio [CHAR LIMIT=50]-->
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing">Sharing Audio</string>
+ <string name="quick_settings_bluetooth_audio_sharing_button_sharing">Sharing audio</string>
<!-- QuickSettings: Bluetooth secondary label for the battery level of a connected device [CHAR LIMIT=20]-->
<string name="quick_settings_bluetooth_secondary_label_battery_level"><xliff:g id="battery_level_as_percentage">%s</xliff:g> battery</string>
diff --git a/packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/Utils.kt b/packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/Utils.kt
index 8979ef1..12d881b 100644
--- a/packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/Utils.kt
+++ b/packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/Utils.kt
@@ -25,7 +25,11 @@
import android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_SOMETHING
import android.content.Context
import android.content.pm.PackageManager
+import android.graphics.Bitmap
+import android.graphics.Canvas
import android.graphics.Insets
+import android.graphics.drawable.BitmapDrawable
+import android.graphics.drawable.Drawable
import android.hardware.biometrics.BiometricManager.Authenticators
import android.hardware.biometrics.PromptInfo
import android.hardware.biometrics.SensorPropertiesInternal
@@ -122,4 +126,26 @@
return windowMetrics?.windowInsets?.getInsets(WindowInsets.Type.navigationBars())
?: Insets.NONE
}
+
+ /** Converts `drawable` to a [Bitmap]. */
+ @JvmStatic
+ fun Drawable?.toBitmap(): Bitmap? {
+ if (this == null) {
+ return null
+ }
+ if (this is BitmapDrawable) {
+ return bitmap
+ }
+ val bitmap: Bitmap =
+ if (intrinsicWidth <= 0 || intrinsicHeight <= 0) {
+ Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888)
+ // Single color bitmap will be created of 1x1 pixel
+ } else {
+ Bitmap.createBitmap(intrinsicWidth, intrinsicHeight, Bitmap.Config.ARGB_8888)
+ }
+ val canvas = Canvas(bitmap)
+ setBounds(0, 0, canvas.width, canvas.height)
+ draw(canvas)
+ return bitmap
+ }
}
diff --git a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
index 86c807b..5dcf161 100644
--- a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
+++ b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
@@ -178,6 +178,7 @@
smallClockOnAttachStateChangeListener =
object : OnAttachStateChangeListener {
var pastVisibility: Int? = null
+
override fun onViewAttachedToWindow(view: View) {
clock.events.onTimeFormatChanged(DateFormat.is24HourFormat(context))
// Match the asing for view.parent's layout classes.
@@ -213,6 +214,7 @@
override fun onViewAttachedToWindow(p0: View) {
clock.events.onTimeFormatChanged(DateFormat.is24HourFormat(context))
}
+
override fun onViewDetachedFromWindow(p0: View) {}
}
clock.largeClock.view.addOnAttachStateChangeListener(largeClockOnAttachStateChangeListener)
@@ -284,8 +286,10 @@
var smallRegionSampler: RegionSampler? = null
private set
+
var largeRegionSampler: RegionSampler? = null
private set
+
var smallTimeListener: TimeListener? = null
var largeTimeListener: TimeListener? = null
val shouldTimeListenerRun: Boolean
@@ -560,7 +564,7 @@
internal fun listenForAnyStateToAodTransition(scope: CoroutineScope): Job {
return scope.launch {
keyguardTransitionInteractor
- .transitionStepsToState(AOD)
+ .transition(Edge.create(to = AOD))
.filter { it.transitionState == TransitionState.STARTED }
.filter { it.from != LOCKSCREEN }
.collect { handleDoze(1f) }
@@ -571,7 +575,7 @@
internal fun listenForAnyStateToLockscreenTransition(scope: CoroutineScope): Job {
return scope.launch {
keyguardTransitionInteractor
- .transitionStepsToState(LOCKSCREEN)
+ .transition(Edge.create(to = LOCKSCREEN))
.filter { it.transitionState == TransitionState.STARTED }
.filter { it.from != AOD }
.collect { handleDoze(0f) }
@@ -586,7 +590,7 @@
internal fun listenForAnyStateToDozingTransition(scope: CoroutineScope): Job {
return scope.launch {
keyguardTransitionInteractor
- .transitionStepsToState(DOZING)
+ .transition(Edge.create(to = DOZING))
.filter { it.transitionState == TransitionState.FINISHED }
.collect { handleDoze(1f) }
}
diff --git a/packages/SystemUI/src/com/android/keyguard/LegacyLockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LegacyLockIconViewController.java
index a9fd340..03b13fe 100644
--- a/packages/SystemUI/src/com/android/keyguard/LegacyLockIconViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/LegacyLockIconViewController.java
@@ -70,7 +70,7 @@
import com.android.systemui.keyguard.MigrateClocksToBlueprint;
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
-import com.android.systemui.keyguard.shared.model.TransitionStep;
+import com.android.systemui.keyguard.shared.model.KeyguardState;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.res.R;
@@ -167,9 +167,9 @@
private LockIconView mView;
@VisibleForTesting
- final Consumer<TransitionStep> mDozeTransitionCallback = (TransitionStep step) -> {
- mInterpolatedDarkAmount = step.getValue();
- mView.setDozeAmount(step.getValue());
+ final Consumer<Float> mDozeTransitionCallback = (Float value) -> {
+ mInterpolatedDarkAmount = value;
+ mView.setDozeAmount(value);
updateBurnInOffsets();
};
@@ -265,7 +265,7 @@
mView.setAccessibilityDelegate(mAccessibilityDelegate);
if (mFeatureFlags.isEnabled(DOZING_MIGRATION_1)) {
- collectFlow(mView, mTransitionInteractor.getDozeAmountTransition(),
+ collectFlow(mView, mTransitionInteractor.transitionValue(KeyguardState.AOD),
mDozeTransitionCallback);
collectFlow(mView, mKeyguardInteractor.isDozing(), mIsDozingCallback);
}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/FullscreenMagnificationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/FullscreenMagnificationController.java
index 0bd6d6e..3c4c003 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/FullscreenMagnificationController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/FullscreenMagnificationController.java
@@ -30,7 +30,12 @@
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.Region;
+import android.os.Handler;
+import android.util.Log;
import android.view.AttachedSurfaceControl;
+import android.view.Display;
+import android.view.IRotationWatcher;
+import android.view.IWindowManager;
import android.view.LayoutInflater;
import android.view.SurfaceControl;
import android.view.SurfaceControlViewHost;
@@ -46,15 +51,18 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.res.R;
+import com.android.systemui.util.leak.RotationUtils;
import java.util.concurrent.Executor;
import java.util.function.Supplier;
class FullscreenMagnificationController implements ComponentCallbacks {
+ private static final String TAG = "FullscreenMagnificationController";
private final Context mContext;
private final AccessibilityManager mAccessibilityManager;
private final WindowManager mWindowManager;
+ private final IWindowManager mIWindowManager;
private Supplier<SurfaceControlViewHost> mScvhSupplier;
private SurfaceControlViewHost mSurfaceControlViewHost = null;
private SurfaceControl mBorderSurfaceControl = null;
@@ -65,33 +73,50 @@
private final int mDisplayId;
private static final Region sEmptyRegion = new Region();
private ValueAnimator mShowHideBorderAnimator;
+ private Handler mHandler;
private Executor mExecutor;
private boolean mFullscreenMagnificationActivated = false;
private final Configuration mConfiguration;
+ private final Runnable mShowBorderRunnable = this::showBorderWithNullCheck;
+ private int mRotation;
+ private final IRotationWatcher mRotationWatcher = new IRotationWatcher.Stub() {
+ @Override
+ public void onRotationChanged(final int rotation) {
+ handleScreenRotation();
+ }
+ };
+ private final long mLongAnimationTimeMs;
FullscreenMagnificationController(
@UiContext Context context,
- Executor executor,
+ @Main Handler handler,
+ @Main Executor executor,
AccessibilityManager accessibilityManager,
WindowManager windowManager,
+ IWindowManager iWindowManager,
Supplier<SurfaceControlViewHost> scvhSupplier) {
- this(context, executor, accessibilityManager, windowManager, scvhSupplier,
- new SurfaceControl.Transaction(), createNullTargetObjectAnimator(context));
+ this(context, handler, executor, accessibilityManager,
+ windowManager, iWindowManager, scvhSupplier,
+ new SurfaceControl.Transaction(), null);
}
@VisibleForTesting
FullscreenMagnificationController(
@UiContext Context context,
+ @Main Handler handler,
@Main Executor executor,
AccessibilityManager accessibilityManager,
WindowManager windowManager,
+ IWindowManager iWindowManager,
Supplier<SurfaceControlViewHost> scvhSupplier,
SurfaceControl.Transaction transaction,
ValueAnimator valueAnimator) {
mContext = context;
+ mHandler = handler;
mExecutor = executor;
mAccessibilityManager = accessibilityManager;
mWindowManager = windowManager;
+ mIWindowManager = iWindowManager;
mWindowBounds = mWindowManager.getCurrentWindowMetrics().getBounds();
mTransaction = transaction;
mScvhSupplier = scvhSupplier;
@@ -101,7 +126,10 @@
R.dimen.magnifier_border_width_fullscreen);
mDisplayId = mContext.getDisplayId();
mConfiguration = new Configuration(context.getResources().getConfiguration());
- mShowHideBorderAnimator = valueAnimator;
+ mLongAnimationTimeMs = mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_longAnimTime);
+ mShowHideBorderAnimator = (valueAnimator == null)
+ ? createNullTargetObjectAnimator() : valueAnimator;
mShowHideBorderAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(@NonNull Animator animation, boolean isReverse) {
@@ -114,15 +142,13 @@
});
}
- private static ValueAnimator createNullTargetObjectAnimator(Context context) {
+ private ValueAnimator createNullTargetObjectAnimator() {
final ValueAnimator valueAnimator =
ObjectAnimator.ofFloat(/* target= */ null, View.ALPHA, 0f, 1f);
Interpolator interpolator = new AccelerateDecelerateInterpolator();
- final long longAnimationDuration = context.getResources().getInteger(
- com.android.internal.R.integer.config_longAnimTime);
valueAnimator.setInterpolator(interpolator);
- valueAnimator.setDuration(longAnimationDuration);
+ valueAnimator.setDuration(mLongAnimationTimeMs);
return valueAnimator;
}
@@ -149,7 +175,11 @@
*/
@UiThread
private void removeFullscreenMagnificationBorder() {
+ if (mHandler.hasCallbacks(mShowBorderRunnable)) {
+ mHandler.removeCallbacks(mShowBorderRunnable);
+ }
mContext.unregisterComponentCallbacks(this);
+
mShowHideBorderAnimator.reverse();
}
@@ -161,6 +191,11 @@
if (mFullscreenBorder != null) {
mFullscreenBorder = null;
+ try {
+ mIWindowManager.removeRotationWatcher(mRotationWatcher);
+ } catch (Exception e) {
+ Log.w(TAG, "Failed to remove rotation watcher", e);
+ }
}
}
@@ -186,6 +221,11 @@
mSurfaceControlViewHost = mScvhSupplier.get();
mSurfaceControlViewHost.setView(mFullscreenBorder, getBorderLayoutParams());
mBorderSurfaceControl = mSurfaceControlViewHost.getSurfacePackage().getSurfaceControl();
+ try {
+ mIWindowManager.watchRotation(mRotationWatcher, Display.DEFAULT_DISPLAY);
+ } catch (Exception e) {
+ Log.w(TAG, "Failed to register rotation watcher", e);
+ }
}
mTransaction
@@ -256,11 +296,55 @@
reCreateWindow = true;
}
- if (mFullscreenBorder != null && reCreateWindow) {
+ if (mFullscreenBorder == null) {
+ return;
+ }
+
+ if (reCreateWindow) {
final int newWidth = mWindowBounds.width() + 2 * mBorderOffset;
final int newHeight = mWindowBounds.height() + 2 * mBorderOffset;
mSurfaceControlViewHost.relayout(newWidth, newHeight);
}
+
+ // Rotating from Landscape to ReverseLandscape will not trigger the config changes in
+ // CONFIG_SCREEN_SIZE and CONFIG_ORIENTATION. Therefore, we would like to check the device
+ // rotation separately.
+ // Since there's a possibility that {@link onConfigurationChanged} comes before
+ // {@link onRotationChanged}, we would like to handle screen rotation in either case that
+ // happens earlier.
+ int newRotation = RotationUtils.getRotation(mContext);
+ if (newRotation != mRotation) {
+ mRotation = newRotation;
+ handleScreenRotation();
+ }
+ }
+
+ private boolean isActivated() {
+ return mFullscreenBorder != null;
+ }
+
+ private void handleScreenRotation() {
+ if (!isActivated()) {
+ return;
+ }
+
+ if (mHandler.hasCallbacks(mShowBorderRunnable)) {
+ mHandler.removeCallbacks(mShowBorderRunnable);
+ }
+
+ // We hide the border immediately as early as possible to beat the redrawing of window
+ // in response to the orientation change so users won't see a weird shape border.
+ mHandler.postAtFrontOfQueue(() -> {
+ mFullscreenBorder.setAlpha(0f);
+ });
+
+ mHandler.postDelayed(mShowBorderRunnable, mLongAnimationTimeMs);
+ }
+
+ private void showBorderWithNullCheck() {
+ if (mShowHideBorderAnimator != null) {
+ mShowHideBorderAnimator.start();
+ }
}
private void updateDimensions() {
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/Magnification.java b/packages/SystemUI/src/com/android/systemui/accessibility/Magnification.java
index 35c2024..e22a4e4 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/Magnification.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/Magnification.java
@@ -34,6 +34,7 @@
import android.os.Message;
import android.util.SparseArray;
import android.view.Display;
+import android.view.IWindowManager;
import android.view.SurfaceControl;
import android.view.SurfaceControlViewHost;
import android.view.WindowManager;
@@ -148,13 +149,19 @@
DisplayIdIndexSupplier<FullscreenMagnificationController> {
private final Context mContext;
+ private final Handler mHandler;
private final Executor mExecutor;
+ private final IWindowManager mIWindowManager;
- FullscreenMagnificationControllerSupplier(Context context, DisplayManager displayManager,
- Executor executor) {
+ FullscreenMagnificationControllerSupplier(Context context,
+ DisplayManager displayManager,
+ Handler handler,
+ Executor executor, IWindowManager iWindowManager) {
super(displayManager);
mContext = context;
+ mHandler = handler;
mExecutor = executor;
+ mIWindowManager = iWindowManager;
}
@Override
@@ -166,9 +173,11 @@
windowContext.setTheme(com.android.systemui.res.R.style.Theme_SystemUI);
return new FullscreenMagnificationController(
windowContext,
+ mHandler,
mExecutor,
windowContext.getSystemService(AccessibilityManager.class),
windowContext.getSystemService(WindowManager.class),
+ mIWindowManager,
scvhSupplier);
}
}
@@ -211,14 +220,16 @@
DisplayIdIndexSupplier<MagnificationSettingsController> mMagnificationSettingsSupplier;
@Inject
- public Magnification(Context context, @Main Handler mainHandler, @Main Executor executor,
+ public Magnification(Context context,
+ @Main Handler mainHandler, @Main Executor executor,
CommandQueue commandQueue, ModeSwitchesController modeSwitchesController,
SysUiState sysUiState, OverviewProxyService overviewProxyService,
SecureSettings secureSettings, DisplayTracker displayTracker,
- DisplayManager displayManager, AccessibilityLogger a11yLogger) {
+ DisplayManager displayManager, AccessibilityLogger a11yLogger,
+ IWindowManager iWindowManager) {
this(context, mainHandler.getLooper(), executor, commandQueue,
modeSwitchesController, sysUiState, overviewProxyService, secureSettings,
- displayTracker, displayManager, a11yLogger);
+ displayTracker, displayManager, a11yLogger, iWindowManager);
}
@VisibleForTesting
@@ -226,7 +237,8 @@
CommandQueue commandQueue, ModeSwitchesController modeSwitchesController,
SysUiState sysUiState, OverviewProxyService overviewProxyService,
SecureSettings secureSettings, DisplayTracker displayTracker,
- DisplayManager displayManager, AccessibilityLogger a11yLogger) {
+ DisplayManager displayManager, AccessibilityLogger a11yLogger,
+ IWindowManager iWindowManager) {
mContext = context;
mHandler = new Handler(looper) {
@Override
@@ -248,7 +260,7 @@
mHandler, mWindowMagnifierCallback,
displayManager, sysUiState, secureSettings);
mFullscreenMagnificationControllerSupplier = new FullscreenMagnificationControllerSupplier(
- context, displayManager, mExecutor);
+ context, displayManager, mHandler, mExecutor, iWindowManager);
mMagnificationSettingsSupplier = new SettingsSupplier(context,
mMagnificationSettingsControllerCallback, displayManager, secureSettings);
diff --git a/packages/SystemUI/src/com/android/systemui/ambient/dagger/AmbientModule.kt b/packages/SystemUI/src/com/android/systemui/ambient/dagger/AmbientModule.kt
index ea00398..b0314d8 100644
--- a/packages/SystemUI/src/com/android/systemui/ambient/dagger/AmbientModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/ambient/dagger/AmbientModule.kt
@@ -16,11 +16,19 @@
package com.android.systemui.ambient.dagger
+import com.android.systemui.ambient.statusbar.dagger.AmbientStatusBarComponent
import com.android.systemui.ambient.touch.dagger.AmbientTouchComponent
import com.android.systemui.ambient.touch.dagger.InputSessionComponent
import dagger.Module
-@Module(subcomponents = [AmbientTouchComponent::class, InputSessionComponent::class])
+@Module(
+ subcomponents =
+ [
+ AmbientStatusBarComponent::class,
+ AmbientTouchComponent::class,
+ InputSessionComponent::class,
+ ]
+)
interface AmbientModule {
companion object {
const val TOUCH_HANDLERS = "touch_handlers"
diff --git a/packages/SystemUI/src/com/android/systemui/ambient/statusbar/dagger/AmbientStatusBarComponent.kt b/packages/SystemUI/src/com/android/systemui/ambient/statusbar/dagger/AmbientStatusBarComponent.kt
new file mode 100644
index 0000000..8ad4d00
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/ambient/statusbar/dagger/AmbientStatusBarComponent.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.ambient.statusbar.dagger
+
+import com.android.systemui.ambient.statusbar.ui.AmbientStatusBarView
+import com.android.systemui.ambient.statusbar.ui.AmbientStatusBarViewController
+import dagger.BindsInstance
+import dagger.Subcomponent
+
+/**
+ * [AmbientStatusBarComponent] can be used for displaying a status bar over ambient surfaces like
+ * the dream or communal hub.
+ */
+@Subcomponent
+interface AmbientStatusBarComponent {
+ @Subcomponent.Factory
+ interface Factory {
+ fun create(
+ @BindsInstance view: AmbientStatusBarView,
+ ): AmbientStatusBarComponent
+ }
+
+ /** Builds a [AmbientStatusBarViewController] */
+ fun getController(): AmbientStatusBarViewController
+}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarView.java b/packages/SystemUI/src/com/android/systemui/ambient/statusbar/ui/AmbientStatusBarView.java
similarity index 93%
rename from packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarView.java
rename to packages/SystemUI/src/com/android/systemui/ambient/statusbar/ui/AmbientStatusBarView.java
index 8e77079..aa96231 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/ambient/statusbar/ui/AmbientStatusBarView.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 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,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.dreams;
+package com.android.systemui.ambient.statusbar.ui;
import android.annotation.IntDef;
import android.annotation.Nullable;
@@ -39,10 +39,10 @@
import java.util.Objects;
/**
- * {@link DreamOverlayStatusBarView} is the view responsible for displaying the status bar in a
+ * {@link AmbientStatusBarView} is the view responsible for displaying the status bar in a
* dream. The status bar displays conditional status icons such as "priority mode" and "no wifi".
*/
-public class DreamOverlayStatusBarView extends ConstraintLayout {
+public class AmbientStatusBarView extends ConstraintLayout {
@Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = { "STATUS_ICON_" }, value = {
@@ -76,20 +76,20 @@
private static final float KEY_SHADOW_ALPHA = 0.35f;
private static final float AMBIENT_SHADOW_ALPHA = 0.4f;
- public DreamOverlayStatusBarView(Context context) {
+ public AmbientStatusBarView(Context context) {
this(context, null);
}
- public DreamOverlayStatusBarView(Context context, AttributeSet attrs) {
+ public AmbientStatusBarView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
- public DreamOverlayStatusBarView(Context context, AttributeSet attrs, int defStyleAttr) {
+ public AmbientStatusBarView(Context context, AttributeSet attrs, int defStyleAttr) {
this(context, attrs, defStyleAttr, 0);
mContext = context;
}
- public DreamOverlayStatusBarView(
+ public AmbientStatusBarView(
Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java b/packages/SystemUI/src/com/android/systemui/ambient/statusbar/ui/AmbientStatusBarViewController.java
similarity index 86%
rename from packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java
rename to packages/SystemUI/src/com/android/systemui/ambient/statusbar/ui/AmbientStatusBarViewController.java
index da72a56..a242d5a 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/ambient/statusbar/ui/AmbientStatusBarViewController.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 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,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.dreams;
+package com.android.systemui.ambient.statusbar.ui;
import static com.android.systemui.util.kotlin.JavaAdapterKt.collectFlow;
@@ -31,20 +31,22 @@
import androidx.annotation.VisibleForTesting;
import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.dreams.DreamLogger;
+import com.android.systemui.dreams.DreamOverlayNotificationCountProvider;
+import com.android.systemui.dreams.DreamOverlayStateController;
+import com.android.systemui.dreams.DreamOverlayStatusBarItemsProvider;
import com.android.systemui.dreams.DreamOverlayStatusBarItemsProvider.StatusBarItem;
-import com.android.systemui.dreams.dagger.DreamOverlayComponent;
import com.android.systemui.log.LogBuffer;
import com.android.systemui.log.dagger.DreamLog;
import com.android.systemui.res.R;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.CrossFadeHelper;
-import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository;
+import com.android.systemui.statusbar.pipeline.wifi.domain.interactor.WifiInteractor;
import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel;
import com.android.systemui.statusbar.policy.IndividualSensorPrivacyController;
import com.android.systemui.statusbar.policy.NextAlarmController;
import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.statusbar.window.StatusBarWindowStateController;
-import com.android.systemui.touch.TouchInsetManager;
import com.android.systemui.util.ViewController;
import com.android.systemui.util.time.DateFormatUtil;
@@ -59,13 +61,11 @@
import javax.inject.Inject;
/**
- * View controller for {@link DreamOverlayStatusBarView}.
+ * View controller for {@link AmbientStatusBarView}.
*/
-@DreamOverlayComponent.DreamOverlayScope
-public class DreamOverlayStatusBarViewController extends ViewController<DreamOverlayStatusBarView> {
+public class AmbientStatusBarViewController extends ViewController<AmbientStatusBarView> {
private static final String TAG = "DreamStatusBarCtrl";
- private final TouchInsetManager.TouchInsetSession mTouchInsetSession;
private final NextAlarmController mNextAlarmController;
private final AlarmManager mAlarmManager;
private final Resources mResources;
@@ -76,7 +76,7 @@
private final ZenModeController mZenModeController;
private final DreamOverlayStateController mDreamOverlayStateController;
private final UserTracker mUserTracker;
- private final WifiRepository mWifiRepository;
+ private final WifiInteractor mWifiInteractor;
private final StatusBarWindowStateController mStatusBarWindowStateController;
private final DreamOverlayStatusBarItemsProvider mStatusBarItemsProvider;
private final Executor mMainExecutor;
@@ -115,7 +115,7 @@
private final DreamOverlayNotificationCountProvider.Callback mNotificationCountCallback =
notificationCount -> showIcon(
- DreamOverlayStatusBarView.STATUS_ICON_NOTIFICATIONS,
+ AmbientStatusBarView.STATUS_ICON_NOTIFICATIONS,
notificationCount > 0,
notificationCount > 0
? buildNotificationsContentDescription(notificationCount)
@@ -125,11 +125,10 @@
this::onStatusBarItemsChanged;
@Inject
- public DreamOverlayStatusBarViewController(
- DreamOverlayStatusBarView view,
+ public AmbientStatusBarViewController(
+ AmbientStatusBarView view,
@Main Resources resources,
@Main Executor mainExecutor,
- TouchInsetManager.TouchInsetSession touchInsetSession,
AlarmManager alarmManager,
NextAlarmController nextAlarmController,
DateFormatUtil dateFormatUtil,
@@ -140,12 +139,11 @@
DreamOverlayStatusBarItemsProvider statusBarItemsProvider,
DreamOverlayStateController dreamOverlayStateController,
UserTracker userTracker,
- WifiRepository wifiRepository,
+ WifiInteractor wifiInteractor,
@DreamLog LogBuffer logBuffer) {
super(view);
mResources = resources;
mMainExecutor = mainExecutor;
- mTouchInsetSession = touchInsetSession;
mAlarmManager = alarmManager;
mNextAlarmController = nextAlarmController;
mDateFormatUtil = dateFormatUtil;
@@ -156,7 +154,7 @@
mZenModeController = zenModeController;
mDreamOverlayStateController = dreamOverlayStateController;
mUserTracker = userTracker;
- mWifiRepository = wifiRepository;
+ mWifiInteractor = wifiInteractor;
mLogger = new DreamLogger(logBuffer, TAG);
// Register to receive show/hide updates for the system status bar. Our custom status bar
@@ -170,7 +168,7 @@
collectFlow(
mView,
- mWifiRepository.getWifiNetwork(),
+ mWifiInteractor.getWifiNetwork(),
network -> updateWifiUnavailableStatusIcon(
network instanceof WifiNetworkModel.Active));
@@ -202,7 +200,6 @@
mView.removeAllExtraStatusBarItemViews();
mDreamOverlayStateController.setDreamOverlayStatusBarVisible(false);
mDreamOverlayStateController.removeCallback(mDreamOverlayStateCallback);
- mTouchInsetSession.clear();
mIsAttached = false;
}
@@ -212,7 +209,7 @@
*
* No-op if the dream overlay status bar should not be shown.
*/
- protected void setFadeAmount(float fadeAmount, boolean fadingOut) {
+ public void setFadeAmount(float fadeAmount, boolean fadingOut) {
updateVisibility();
if (mView.getVisibility() != View.VISIBLE) {
@@ -240,7 +237,7 @@
@VisibleForTesting
void updateWifiUnavailableStatusIcon(boolean available) {
- showIcon(DreamOverlayStatusBarView.STATUS_ICON_WIFI_UNAVAILABLE, !available,
+ showIcon(AmbientStatusBarView.STATUS_ICON_WIFI_UNAVAILABLE, !available,
R.string.wifi_unavailable_dream_overlay_content_description);
}
@@ -249,13 +246,13 @@
mAlarmManager.getNextAlarmClock(mUserTracker.getUserId());
final boolean hasAlarm = alarm != null && alarm.getTriggerTime() > 0;
showIcon(
- DreamOverlayStatusBarView.STATUS_ICON_ALARM_SET,
+ AmbientStatusBarView.STATUS_ICON_ALARM_SET,
hasAlarm,
hasAlarm ? buildAlarmContentDescription(alarm) : null);
}
private void updateAssistantAttentionIcon() {
- showIcon(DreamOverlayStatusBarView.STATUS_ICON_ASSISTANT_ATTENTION_ACTIVE,
+ showIcon(AmbientStatusBarView.STATUS_ICON_ASSISTANT_ATTENTION_ACTIVE,
mDreamOverlayStateController.hasAssistantAttention(),
R.string.assistant_attention_content_description);
}
@@ -284,17 +281,17 @@
.isSensorBlocked(SensorPrivacyManager.Sensors.MICROPHONE);
final boolean cameraBlocked = mSensorPrivacyController
.isSensorBlocked(SensorPrivacyManager.Sensors.CAMERA);
- @DreamOverlayStatusBarView.StatusIconType int iconType = Resources.ID_NULL;
+ @AmbientStatusBarView.StatusIconType int iconType = Resources.ID_NULL;
showIcon(
- DreamOverlayStatusBarView.STATUS_ICON_CAMERA_DISABLED,
+ AmbientStatusBarView.STATUS_ICON_CAMERA_DISABLED,
!micBlocked && cameraBlocked,
R.string.camera_blocked_dream_overlay_content_description);
showIcon(
- DreamOverlayStatusBarView.STATUS_ICON_MIC_DISABLED,
+ AmbientStatusBarView.STATUS_ICON_MIC_DISABLED,
micBlocked && !cameraBlocked,
R.string.microphone_blocked_dream_overlay_content_description);
showIcon(
- DreamOverlayStatusBarView.STATUS_ICON_MIC_CAMERA_DISABLED,
+ AmbientStatusBarView.STATUS_ICON_MIC_CAMERA_DISABLED,
micBlocked && cameraBlocked,
R.string.camera_and_microphone_blocked_dream_overlay_content_description);
}
@@ -308,24 +305,24 @@
private void updatePriorityModeStatusIcon() {
showIcon(
- DreamOverlayStatusBarView.STATUS_ICON_PRIORITY_MODE_ON,
+ AmbientStatusBarView.STATUS_ICON_PRIORITY_MODE_ON,
mZenModeController.getZen() != Settings.Global.ZEN_MODE_OFF,
R.string.priority_mode_dream_overlay_content_description);
}
- private void showIcon(@DreamOverlayStatusBarView.StatusIconType int iconType, boolean show,
+ private void showIcon(@AmbientStatusBarView.StatusIconType int iconType, boolean show,
int contentDescriptionResId) {
showIcon(iconType, show, mResources.getString(contentDescriptionResId));
}
private void showIcon(
- @DreamOverlayStatusBarView.StatusIconType int iconType,
+ @AmbientStatusBarView.StatusIconType int iconType,
boolean show,
@Nullable String contentDescription) {
mMainExecutor.execute(() -> {
if (mIsAttached) {
mLogger.logShowOrHideStatusBarItem(
- show, DreamOverlayStatusBarView.getLoggableStatusIconType(iconType));
+ show, AmbientStatusBarView.getLoggableStatusIconType(iconType));
mView.showIcon(iconType, show, contentDescription);
}
});
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerLegacy.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerLegacy.kt
index 298b87d..c3d9240 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerLegacy.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerLegacy.kt
@@ -39,7 +39,6 @@
import com.android.systemui.keyguard.shared.model.KeyguardState.GONE
import com.android.systemui.keyguard.shared.model.KeyguardState.OCCLUDED
import com.android.systemui.keyguard.shared.model.KeyguardState.PRIMARY_BOUNCER
-import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.res.R
@@ -59,7 +58,6 @@
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.Job
-import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch
/** Class that coordinates non-HBM animations during keyguard authentication. */
@@ -307,27 +305,12 @@
@VisibleForTesting
suspend fun listenForLockscreenAodTransitions(scope: CoroutineScope): Job {
return scope.launch {
- transitionInteractor.dozeAmountTransition.collect { transitionStep ->
- if (
- transitionStep.from == AOD &&
- transitionStep.transitionState == TransitionState.CANCELED
- ) {
- if (transitionInteractor.startedKeyguardTransitionStep.first().to != AOD) {
- // If the next started transition isn't transitioning back to AOD, force
- // doze amount to be 0f (as if the transition to the lockscreen completed).
- view.onDozeAmountChanged(
- 0f,
- 0f,
- UdfpsKeyguardViewLegacy.ANIMATION_NONE,
- )
- }
- } else {
- view.onDozeAmountChanged(
- transitionStep.value,
- transitionStep.value,
- UdfpsKeyguardViewLegacy.ANIMATION_BETWEEN_AOD_AND_LOCKSCREEN,
- )
- }
+ transitionInteractor.transitionValue(AOD).collect {
+ view.onDozeAmountChanged(
+ it,
+ it,
+ UdfpsKeyguardViewLegacy.ANIMATION_BETWEEN_AOD_AND_LOCKSCREEN,
+ )
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/DisplayStateRepository.kt b/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/DisplayStateRepository.kt
index 9b14d6f..2fa4a89 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/DisplayStateRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/DisplayStateRepository.kt
@@ -139,9 +139,10 @@
}
.stateIn(
backgroundScope,
- started = SharingStarted.WhileSubscribed(),
+ started = SharingStarted.Eagerly,
initialValue = false,
)
+
private fun dpiFromPx(size: Float, densityDpi: Int): Float {
val densityRatio = densityDpi.toFloat() / DisplayMetrics.DENSITY_DEFAULT
return size / densityRatio
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/domain/model/BiometricPromptRequest.kt b/packages/SystemUI/src/com/android/systemui/biometrics/domain/model/BiometricPromptRequest.kt
index 4f96c1e..348b423 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/domain/model/BiometricPromptRequest.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/domain/model/BiometricPromptRequest.kt
@@ -40,8 +40,7 @@
operationInfo = operationInfo,
showEmergencyCallButton = info.isShowEmergencyCallButton
) {
- val logoRes: Int = info.logoRes
- val logoBitmap: Bitmap? = info.logoBitmap
+ val logoBitmap: Bitmap? = info.logo
val logoDescription: String? = info.logoDescription
val negativeButtonText: String = info.negativeButtonText?.toString() ?: ""
val componentNameForConfirmDeviceCredentialActivity: ComponentName? =
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewSizeBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewSizeBinder.kt
index 628b533..b4d53d0 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewSizeBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewSizeBinder.kt
@@ -51,6 +51,7 @@
import com.android.systemui.biometrics.ui.viewmodel.isMedium
import com.android.systemui.biometrics.ui.viewmodel.isNullOrNotSmall
import com.android.systemui.biometrics.ui.viewmodel.isSmall
+import com.android.systemui.biometrics.ui.viewmodel.isTop
import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.res.R
import kotlin.math.abs
@@ -100,13 +101,13 @@
val iconHolderView = view.requireViewById<View>(R.id.biometric_icon)
val panelView = view.requireViewById<View>(R.id.panel)
val cornerRadius = view.resources.getDimension(R.dimen.biometric_dialog_corner_size)
- val cornerRadiusPx =
+ val pxToDp =
TypedValue.applyDimension(
- TypedValue.COMPLEX_UNIT_DIP,
- cornerRadius,
- view.resources.displayMetrics
- )
- .toInt()
+ TypedValue.COMPLEX_UNIT_DIP,
+ 1f,
+ view.resources.displayMetrics
+ )
+ val cornerRadiusPx = (pxToDp * cornerRadius).toInt()
var currentSize: PromptSize? = null
var currentPosition: PromptPosition = PromptPosition.Bottom
@@ -132,18 +133,10 @@
cornerRadiusPx.toFloat()
)
}
+ PromptPosition.Bottom,
PromptPosition.Top -> {
outline.setRoundRect(
0,
- -cornerRadiusPx,
- view.width,
- view.height,
- cornerRadiusPx.toFloat()
- )
- }
- PromptPosition.Bottom -> {
- outline.setRoundRect(
- 0,
0,
view.width,
view.height + cornerRadiusPx,
@@ -308,6 +301,7 @@
}
}
}
+
lifecycleScope.launch {
viewModel.iconSize.collect { iconSize ->
iconHolderView.layoutParams.width = iconSize.first
@@ -385,6 +379,7 @@
}
}
}
+
lifecycleScope.launch {
combine(viewModel.hideSensorIcon, viewModel.size, ::Pair).collect {
(hideSensorIcon, size) ->
@@ -415,6 +410,33 @@
R.id.rightGuideline,
ConstraintSet.RIGHT
)
+ } else if (position.isTop) {
+ // Top position is only used for 180 rotation Udfps
+ // Requires repositioning due to sensor location at top of screen
+ mediumConstraintSet.connect(
+ R.id.scrollView,
+ ConstraintSet.TOP,
+ R.id.indicator,
+ ConstraintSet.BOTTOM
+ )
+ mediumConstraintSet.connect(
+ R.id.scrollView,
+ ConstraintSet.BOTTOM,
+ R.id.button_bar,
+ ConstraintSet.TOP
+ )
+ mediumConstraintSet.connect(
+ R.id.panel,
+ ConstraintSet.TOP,
+ R.id.biometric_icon,
+ ConstraintSet.TOP
+ )
+ mediumConstraintSet.setMargin(
+ R.id.panel,
+ ConstraintSet.TOP,
+ (-24 * pxToDp).toInt()
+ )
+ mediumConstraintSet.setVerticalBias(R.id.scrollView, 0f)
}
when {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt
index a39a74f..68a3f5d 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt
@@ -262,7 +262,8 @@
_forceLargeSize,
displayStateInteractor.isLargeScreen,
displayStateInteractor.currentRotation,
- ) { forceLarge, isLargeScreen, rotation ->
+ modalities
+ ) { forceLarge, isLargeScreen, rotation, modalities ->
when {
forceLarge ||
isLargeScreen ||
@@ -270,7 +271,8 @@
PromptPosition.Bottom
rotation == DisplayRotation.ROTATION_90 -> PromptPosition.Right
rotation == DisplayRotation.ROTATION_270 -> PromptPosition.Left
- rotation == DisplayRotation.ROTATION_180 -> PromptPosition.Top
+ rotation == DisplayRotation.ROTATION_180 && modalities.hasUdfps ->
+ PromptPosition.Top
else -> PromptPosition.Bottom
}
}
@@ -362,7 +364,14 @@
landscapeMediumBottomPadding
)
}
- PromptPosition.Top -> Rect()
+ PromptPosition.Top ->
+ if (size.isSmall) {
+ Rect(0, 0, 0, portraitSmallBottomPadding)
+ } else if (size.isMedium && modalities.hasUdfps) {
+ Rect(0, 0, 0, sensorBounds.bottom)
+ } else {
+ Rect(0, 0, 0, portraitMediumBottomPadding)
+ }
}
}
.distinctUntilChanged()
@@ -504,7 +513,6 @@
.map {
when {
!(customBiometricPrompt() && constraintBp()) || it == null -> null
- it.logoRes != -1 -> context.resources.getDrawable(it.logoRes, context.theme)
it.logoBitmap != null -> BitmapDrawable(context.resources, it.logoBitmap)
else -> context.getUserBadgedIcon(it, iconProvider, activityTaskManager)
}
diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogLogger.kt b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogLogger.kt
index c30aea0..72312b8 100644
--- a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogLogger.kt
@@ -16,6 +16,7 @@
package com.android.systemui.bluetooth.qsdialog
+import android.bluetooth.BluetoothDevice
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.core.LogLevel.DEBUG
import com.android.systemui.log.dagger.BluetoothTileDialogLog
@@ -103,4 +104,29 @@
fun logDeviceUiUpdate(duration: Long) =
logBuffer.log(TAG, DEBUG, { long1 = duration }, { "DeviceUiUpdate. duration=$long1" })
+
+ fun logDeviceClickInAudioSharingWhenEnabled(inAudioSharing: Boolean) {
+ logBuffer.log(
+ TAG,
+ DEBUG,
+ { str1 = inAudioSharing.toString() },
+ { "DeviceClick. in audio sharing=$str1" }
+ )
+ }
+
+ fun logConnectedLeByGroupId(map: Map<Int, List<BluetoothDevice>>) {
+ logBuffer.log(TAG, DEBUG, { str1 = map.toString() }, { "ConnectedLeByGroupId. map=$str1" })
+ }
+
+ fun logLaunchSettingsCriteriaMatched(criteria: String, deviceItem: DeviceItem) {
+ logBuffer.log(
+ TAG,
+ DEBUG,
+ {
+ str1 = criteria
+ str2 = deviceItem.toString()
+ },
+ { "$str1. deviceItem=$str2" }
+ )
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogUiEvent.kt b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogUiEvent.kt
index b592b8e..4a358c0 100644
--- a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogUiEvent.kt
+++ b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogUiEvent.kt
@@ -35,7 +35,17 @@
CONNECTED_OTHER_DEVICE_DISCONNECT(1508),
@UiEvent(doc = "The auto on toggle is clicked") BLUETOOTH_AUTO_ON_TOGGLE_CLICKED(1617),
@UiEvent(doc = "The audio sharing button is clicked")
- BLUETOOTH_AUDIO_SHARING_BUTTON_CLICKED(1700);
+ BLUETOOTH_AUDIO_SHARING_BUTTON_CLICKED(1700),
+ @UiEvent(doc = "Currently broadcasting and a LE audio supported device is clicked")
+ LAUNCH_SETTINGS_IN_SHARING_LE_DEVICE_CLICKED(1717),
+ @UiEvent(doc = "Currently broadcasting and a non-LE audio supported device is clicked")
+ LAUNCH_SETTINGS_IN_SHARING_NON_LE_DEVICE_CLICKED(1718),
+ @UiEvent(
+ doc = "Not broadcasting, having one connected, another saved LE audio device is clicked"
+ )
+ LAUNCH_SETTINGS_NOT_SHARING_SAVED_LE_DEVICE_CLICKED(1719),
+ @UiEvent(doc = "Not broadcasting, one of the two connected LE audio devices is clicked")
+ LAUNCH_SETTINGS_NOT_SHARING_CONNECTED_LE_DEVICE_CLICKED(1720);
override fun getId() = metricId
}
diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItemActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItemActionInteractor.kt
index 9311760..4dafa93 100644
--- a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItemActionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItemActionInteractor.kt
@@ -16,32 +16,87 @@
package com.android.systemui.bluetooth.qsdialog
+import android.bluetooth.BluetoothDevice
+import android.bluetooth.BluetoothProfile
+import android.content.Intent
+import android.os.Bundle
+import android.provider.Settings
import com.android.internal.logging.UiEventLogger
+import com.android.settingslib.bluetooth.A2dpProfile
+import com.android.settingslib.bluetooth.BluetoothUtils
+import com.android.settingslib.bluetooth.HeadsetProfile
+import com.android.settingslib.bluetooth.HearingAidProfile
+import com.android.settingslib.bluetooth.LeAudioProfile
+import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast
+import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant
+import com.android.settingslib.bluetooth.LocalBluetoothManager
+import com.android.systemui.animation.DialogTransitionAnimator
+import com.android.systemui.bluetooth.qsdialog.DeviceItemActionInteractor.LaunchSettingsCriteria.Companion.getCurrentConnectedLeByGroupId
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.statusbar.phone.SystemUIDialog
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.withContext
-/** Defines interface for click handling of a DeviceItem. */
-interface DeviceItemActionInteractor {
- suspend fun onClick(deviceItem: DeviceItem, dialog: SystemUIDialog)
-}
-
@SysUISingleton
-open class DeviceItemActionInteractorImpl
+class DeviceItemActionInteractor
@Inject
constructor(
+ private val activityStarter: ActivityStarter,
+ private val dialogTransitionAnimator: DialogTransitionAnimator,
+ private val localBluetoothManager: LocalBluetoothManager?,
@Background private val backgroundDispatcher: CoroutineDispatcher,
private val logger: BluetoothTileDialogLogger,
private val uiEventLogger: UiEventLogger,
-) : DeviceItemActionInteractor {
+) {
+ private val leAudioProfile: LeAudioProfile?
+ get() = localBluetoothManager?.profileManager?.leAudioProfile
- override suspend fun onClick(deviceItem: DeviceItem, dialog: SystemUIDialog) {
+ private val assistantProfile: LocalBluetoothLeBroadcastAssistant?
+ get() = localBluetoothManager?.profileManager?.leAudioBroadcastAssistantProfile
+
+ private val launchSettingsCriteriaList: List<LaunchSettingsCriteria>
+ get() =
+ listOf(
+ InSharingClickedNoSource(localBluetoothManager, backgroundDispatcher, logger),
+ NotSharingClickedNonConnect(
+ leAudioProfile,
+ assistantProfile,
+ backgroundDispatcher,
+ logger
+ ),
+ NotSharingClickedConnected(
+ leAudioProfile,
+ assistantProfile,
+ backgroundDispatcher,
+ logger
+ )
+ )
+
+ suspend fun onClick(deviceItem: DeviceItem, dialog: SystemUIDialog) {
withContext(backgroundDispatcher) {
logger.logDeviceClick(deviceItem.cachedBluetoothDevice.address, deviceItem.type)
+ if (
+ BluetoothUtils.isAudioSharingEnabled() &&
+ localBluetoothManager != null &&
+ leAudioProfile != null &&
+ assistantProfile != null
+ ) {
+ val inAudioSharing = BluetoothUtils.isBroadcasting(localBluetoothManager)
+ logger.logDeviceClickInAudioSharingWhenEnabled(inAudioSharing)
+ val criteriaMatched =
+ launchSettingsCriteriaList.firstOrNull {
+ it.matched(inAudioSharing, deviceItem)
+ }
+ if (criteriaMatched != null) {
+ uiEventLogger.log(criteriaMatched.getClickUiEvent(deviceItem))
+ launchSettings(deviceItem.cachedBluetoothDevice.device, dialog)
+ return@withContext
+ }
+ }
deviceItem.cachedBluetoothDevice.apply {
when (deviceItem.type) {
DeviceItemType.ACTIVE_MEDIA_BLUETOOTH_DEVICE -> {
@@ -69,4 +124,184 @@
}
}
}
+
+ private fun launchSettings(device: BluetoothDevice, dialog: SystemUIDialog) {
+ val intent =
+ Intent(Settings.ACTION_BLUETOOTH_SETTINGS).apply {
+ putExtra(
+ EXTRA_SHOW_FRAGMENT_ARGUMENTS,
+ Bundle().apply {
+ putParcelable(LocalBluetoothLeBroadcast.EXTRA_BLUETOOTH_DEVICE, device)
+ }
+ )
+ }
+ intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TASK
+ activityStarter.postStartActivityDismissingKeyguard(
+ intent,
+ 0,
+ dialogTransitionAnimator.createActivityTransitionController(dialog)
+ )
+ }
+
+ private interface LaunchSettingsCriteria {
+ suspend fun matched(inAudioSharing: Boolean, deviceItem: DeviceItem): Boolean
+
+ suspend fun getClickUiEvent(deviceItem: DeviceItem): BluetoothTileDialogUiEvent
+
+ companion object {
+ suspend fun getCurrentConnectedLeByGroupId(
+ leAudioProfile: LeAudioProfile,
+ assistantProfile: LocalBluetoothLeBroadcastAssistant,
+ @Background backgroundDispatcher: CoroutineDispatcher,
+ logger: BluetoothTileDialogLogger,
+ ): Map<Int, List<BluetoothDevice>> {
+ return withContext(backgroundDispatcher) {
+ assistantProfile
+ .getDevicesMatchingConnectionStates(
+ intArrayOf(BluetoothProfile.STATE_CONNECTED)
+ )
+ ?.filterNotNull()
+ ?.groupBy { leAudioProfile.getGroupId(it) }
+ ?.also { logger.logConnectedLeByGroupId(it) } ?: emptyMap()
+ }
+ }
+ }
+ }
+
+ private class InSharingClickedNoSource(
+ private val localBluetoothManager: LocalBluetoothManager?,
+ @Background private val backgroundDispatcher: CoroutineDispatcher,
+ private val logger: BluetoothTileDialogLogger,
+ ) : LaunchSettingsCriteria {
+ // If currently broadcasting and the clicked device is not connected to the source
+ override suspend fun matched(inAudioSharing: Boolean, deviceItem: DeviceItem): Boolean {
+ return withContext(backgroundDispatcher) {
+ val matched =
+ inAudioSharing &&
+ deviceItem.isMediaDevice &&
+ !BluetoothUtils.hasConnectedBroadcastSource(
+ deviceItem.cachedBluetoothDevice,
+ localBluetoothManager
+ )
+
+ if (matched) {
+ logger.logLaunchSettingsCriteriaMatched("InSharingClickedNoSource", deviceItem)
+ }
+
+ matched
+ }
+ }
+
+ override suspend fun getClickUiEvent(deviceItem: DeviceItem) =
+ if (deviceItem.isLeAudioSupported)
+ BluetoothTileDialogUiEvent.LAUNCH_SETTINGS_IN_SHARING_LE_DEVICE_CLICKED
+ else BluetoothTileDialogUiEvent.LAUNCH_SETTINGS_IN_SHARING_NON_LE_DEVICE_CLICKED
+ }
+
+ private class NotSharingClickedNonConnect(
+ private val leAudioProfile: LeAudioProfile?,
+ private val assistantProfile: LocalBluetoothLeBroadcastAssistant?,
+ @Background private val backgroundDispatcher: CoroutineDispatcher,
+ private val logger: BluetoothTileDialogLogger,
+ ) : LaunchSettingsCriteria {
+ // If not broadcasting, having one device connected, and clicked on a not yet connected LE
+ // audio device
+ override suspend fun matched(inAudioSharing: Boolean, deviceItem: DeviceItem): Boolean {
+ return withContext(backgroundDispatcher) {
+ val matched =
+ leAudioProfile?.let { leAudio ->
+ assistantProfile?.let { assistant ->
+ !inAudioSharing &&
+ getCurrentConnectedLeByGroupId(
+ leAudio,
+ assistant,
+ backgroundDispatcher,
+ logger
+ )
+ .size == 1 &&
+ deviceItem.isNotConnectedLeAudioSupported
+ }
+ } ?: false
+
+ if (matched) {
+ logger.logLaunchSettingsCriteriaMatched(
+ "NotSharingClickedNonConnect",
+ deviceItem
+ )
+ }
+
+ matched
+ }
+ }
+
+ override suspend fun getClickUiEvent(deviceItem: DeviceItem) =
+ BluetoothTileDialogUiEvent.LAUNCH_SETTINGS_NOT_SHARING_SAVED_LE_DEVICE_CLICKED
+ }
+
+ private class NotSharingClickedConnected(
+ private val leAudioProfile: LeAudioProfile?,
+ private val assistantProfile: LocalBluetoothLeBroadcastAssistant?,
+ @Background private val backgroundDispatcher: CoroutineDispatcher,
+ private val logger: BluetoothTileDialogLogger,
+ ) : LaunchSettingsCriteria {
+ // If not broadcasting, having two device connected, clicked on any connected LE audio
+ // devices
+ override suspend fun matched(inAudioSharing: Boolean, deviceItem: DeviceItem): Boolean {
+ return withContext(backgroundDispatcher) {
+ val matched =
+ leAudioProfile?.let { leAudio ->
+ assistantProfile?.let { assistant ->
+ !inAudioSharing &&
+ getCurrentConnectedLeByGroupId(
+ leAudio,
+ assistant,
+ backgroundDispatcher,
+ logger
+ )
+ .size == 2 &&
+ deviceItem.isActiveOrConnectedLeAudioSupported
+ }
+ } ?: false
+
+ if (matched) {
+ logger.logLaunchSettingsCriteriaMatched(
+ "NotSharingClickedConnected",
+ deviceItem
+ )
+ }
+
+ matched
+ }
+ }
+
+ override suspend fun getClickUiEvent(deviceItem: DeviceItem) =
+ BluetoothTileDialogUiEvent.LAUNCH_SETTINGS_NOT_SHARING_CONNECTED_LE_DEVICE_CLICKED
+ }
+
+ private companion object {
+ const val EXTRA_SHOW_FRAGMENT_ARGUMENTS = ":settings:show_fragment_args"
+
+ val DeviceItem.isLeAudioSupported: Boolean
+ get() =
+ cachedBluetoothDevice.profiles.any { profile ->
+ profile is LeAudioProfile && profile.isEnabled(cachedBluetoothDevice.device)
+ }
+
+ val DeviceItem.isNotConnectedLeAudioSupported: Boolean
+ get() = type == DeviceItemType.SAVED_BLUETOOTH_DEVICE && isLeAudioSupported
+
+ val DeviceItem.isActiveOrConnectedLeAudioSupported: Boolean
+ get() =
+ (type == DeviceItemType.ACTIVE_MEDIA_BLUETOOTH_DEVICE ||
+ type == DeviceItemType.AVAILABLE_MEDIA_BLUETOOTH_DEVICE) && isLeAudioSupported
+
+ val DeviceItem.isMediaDevice: Boolean
+ get() =
+ cachedBluetoothDevice.connectableProfiles.any {
+ it is A2dpProfile ||
+ it is HearingAidProfile ||
+ it is LeAudioProfile ||
+ it is HeadsetProfile
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/CommunalDreamStartable.kt b/packages/SystemUI/src/com/android/systemui/communal/CommunalDreamStartable.kt
index 8993a3b..38f51da 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/CommunalDreamStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/CommunalDreamStartable.kt
@@ -19,23 +19,25 @@
import android.annotation.SuppressLint
import android.app.DreamManager
import com.android.systemui.CoreStartable
-import com.android.systemui.Flags.glanceableHubAllowKeyguardWhenDreaming
import com.android.systemui.Flags.communalHub
+import com.android.systemui.Flags.glanceableHubAllowKeyguardWhenDreaming
import com.android.systemui.Flags.restartDreamOnUnocclude
-import com.android.systemui.communal.domain.interactor.CommunalInteractor
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
+import com.android.systemui.keyguard.shared.model.Edge
import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.shared.model.TransitionState
+import com.android.systemui.keyguard.shared.model.filterState
import com.android.systemui.power.domain.interactor.PowerInteractor
-import com.android.systemui.util.kotlin.Utils.Companion.sample
-import com.android.systemui.util.kotlin.sample
+import com.android.systemui.scene.shared.model.Scenes
+import com.android.systemui.util.kotlin.Utils.Companion.sampleFilter
+import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
-import javax.inject.Inject
/**
* A [CoreStartable] responsible for automatically starting the dream when the communal hub is
@@ -48,7 +50,6 @@
private val powerInteractor: PowerInteractor,
private val keyguardInteractor: KeyguardInteractor,
private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
- private val communalInteractor: CommunalInteractor,
private val dreamManager: DreamManager,
@Background private val bgScope: CoroutineScope,
) : CoreStartable {
@@ -60,31 +61,28 @@
// Return to dream from occluded when not already dreaming.
if (restartDreamOnUnocclude()) {
- keyguardTransitionInteractor.startedKeyguardTransitionStep
- .sample(keyguardInteractor.isDreaming, ::Pair)
- .filter {
- it.first.from == KeyguardState.OCCLUDED &&
- it.first.to == KeyguardState.DREAMING &&
- !it.second
- }
+ keyguardTransitionInteractor
+ .transition(Edge.create(from = KeyguardState.OCCLUDED, to = KeyguardState.DREAMING))
+ .filterState(TransitionState.STARTED)
+ .sampleFilter(keyguardInteractor.isDreaming) { isDreaming -> !isDreaming }
.onEach { dreamManager.startDream() }
.launchIn(bgScope)
}
// Restart the dream underneath the hub in order to support the ability to swipe
// away the hub to enter the dream.
- keyguardTransitionInteractor.finishedKeyguardState
- .sample(powerInteractor.isAwake, keyguardInteractor.isDreaming)
- .onEach { (finishedState, isAwake, dreaming) ->
- if (
- finishedState == KeyguardState.GLANCEABLE_HUB &&
- !dreaming &&
- !glanceableHubAllowKeyguardWhenDreaming() &&
- dreamManager.canStartDreaming(isAwake)
- ) {
- dreamManager.startDream()
- }
+ keyguardTransitionInteractor
+ .transition(
+ edge = Edge.create(to = Scenes.Communal),
+ edgeWithoutSceneContainer = Edge.create(to = KeyguardState.GLANCEABLE_HUB)
+ )
+ .filterState(TransitionState.FINISHED)
+ .sampleFilter(powerInteractor.isAwake) { isAwake ->
+ dreamManager.canStartDreaming(isAwake)
}
+ .sampleFilter(keyguardInteractor.isDreaming) { isDreaming -> !isDreaming }
+ .filter { !glanceableHubAllowKeyguardWhenDreaming() }
+ .onEach { dreamManager.startDream() }
.launchIn(bgScope)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalSceneRepository.kt b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalSceneRepository.kt
index 260dcba..7a4006d 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalSceneRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalSceneRepository.kt
@@ -28,6 +28,7 @@
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
@@ -51,7 +52,7 @@
fun changeScene(toScene: SceneKey, transitionKey: TransitionKey? = null)
/** Immediately snaps to the desired scene. */
- fun snapToScene(toScene: SceneKey)
+ fun snapToScene(toScene: SceneKey, delayMillis: Long = 0)
/**
* Updates the transition state of the hub [SceneTransitionLayout].
@@ -92,10 +93,11 @@
}
}
- override fun snapToScene(toScene: SceneKey) {
+ override fun snapToScene(toScene: SceneKey, delayMillis: Long) {
applicationScope.launch {
// SceneTransitionLayout state updates must be triggered on the thread the STL was
// created on.
+ delay(delayMillis)
sceneDataSource.snapToScene(toScene)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
index fdb40fb..3e513f8 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
@@ -46,6 +46,7 @@
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
+import com.android.systemui.keyguard.shared.model.Edge
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.core.Logger
@@ -164,7 +165,7 @@
/** Whether to start dreaming when returning from occluded */
val dreamFromOccluded: Flow<Boolean> =
keyguardTransitionInteractor
- .transitionStepsToState(KeyguardState.OCCLUDED)
+ .transition(Edge.create(to = KeyguardState.OCCLUDED))
.map { it.from == KeyguardState.DREAMING }
.stateIn(scope = applicationScope, SharingStarted.Eagerly, false)
diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSceneInteractor.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSceneInteractor.kt
index 5cfe979..0dab67c 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSceneInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSceneInteractor.kt
@@ -53,8 +53,8 @@
}
/** Immediately snaps to the new scene. */
- fun snapToScene(newScene: SceneKey) {
- communalSceneRepository.snapToScene(newScene)
+ fun snapToScene(newScene: SceneKey, delayMillis: Long = 0) {
+ communalSceneRepository.snapToScene(newScene, delayMillis)
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalTransitionViewModel.kt
index 9114aab..7a20ebc 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalTransitionViewModel.kt
@@ -21,12 +21,14 @@
import com.android.systemui.communal.util.CommunalColors
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
+import com.android.systemui.keyguard.shared.model.Edge
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.ui.viewmodel.DreamingToGlanceableHubTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.GlanceableHubToDreamingTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.GlanceableHubToLockscreenTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.LockscreenToGlanceableHubTransitionViewModel
+import com.android.systemui.scene.shared.model.Scenes
import javax.inject.Inject
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
@@ -53,7 +55,7 @@
// Show UMO on glanceable hub immediately on transition into glanceable hub
private val showUmoFromOccludedToGlanceableHub: Flow<Boolean> =
keyguardTransitionInteractor
- .transitionStepsFromState(KeyguardState.OCCLUDED)
+ .transition(Edge.create(from = KeyguardState.OCCLUDED))
.filter {
it.to == KeyguardState.GLANCEABLE_HUB &&
(it.transitionState == TransitionState.STARTED ||
@@ -63,7 +65,10 @@
private val showUmoFromGlanceableHubToOccluded: Flow<Boolean> =
keyguardTransitionInteractor
- .transitionStepsFromState(KeyguardState.GLANCEABLE_HUB)
+ .transition(
+ edge = Edge.create(from = Scenes.Communal),
+ edgeWithoutSceneContainer = Edge.create(from = KeyguardState.GLANCEABLE_HUB)
+ )
.filter {
it.to == KeyguardState.OCCLUDED &&
(it.transitionState == TransitionState.FINISHED ||
@@ -91,11 +96,12 @@
val showCommunalFromOccluded: Flow<Boolean> = communalInteractor.showCommunalFromOccluded
val transitionFromOccludedEnded =
- keyguardTransitionInteractor.transitionStepsFromState(KeyguardState.OCCLUDED).filter { step
- ->
- step.transitionState == TransitionState.FINISHED ||
- step.transitionState == TransitionState.CANCELED
- }
+ keyguardTransitionInteractor
+ .transition(Edge.create(from = KeyguardState.OCCLUDED))
+ .filter { step ->
+ step.transitionState == TransitionState.FINISHED ||
+ step.transitionState == TransitionState.CANCELED
+ }
val recentsBackgroundColor: Flow<Color?> =
combine(showCommunalFromOccluded, communalColors.backgroundColor) {
diff --git a/packages/SystemUI/src/com/android/systemui/communal/widgets/EditWidgetsActivity.kt b/packages/SystemUI/src/com/android/systemui/communal/widgets/EditWidgetsActivity.kt
index 426f484..50477b1 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/widgets/EditWidgetsActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/widgets/EditWidgetsActivity.kt
@@ -70,8 +70,6 @@
private var shouldOpenWidgetPickerOnStart = false
- private var lockOnDestroy = false
-
private val addWidgetActivityLauncher: ActivityResultLauncher<Intent> =
registerForActivityResult(StartActivityForResult()) { result ->
when (result.resultCode) {
@@ -97,8 +95,7 @@
run { Log.w(TAG, "No AppWidgetProviderInfo found in result.") }
}
}
- }
- ?: run { Log.w(TAG, "No data in result.") }
+ } ?: run { Log.w(TAG, "No data in result.") }
}
else ->
Log.w(
@@ -160,9 +157,9 @@
// Wait for the current scene to be idle on communal.
communalViewModel.isIdleOnCommunal.first { it }
- // Then finish the activity (this helps to avoid a flash of lockscreen when locking
- // in onDestroy()).
- lockOnDestroy = true
+
+ // Lock to go back to the hub after exiting.
+ lockNow()
finish()
}
}
@@ -196,8 +193,6 @@
override fun onDestroy() {
super.onDestroy()
communalViewModel.setEditModeOpen(false)
-
- if (lockOnDestroy) lockNow()
}
private fun lockNow() {
diff --git a/packages/SystemUI/src/com/android/systemui/communal/widgets/SmartspaceAppWidgetHostView.kt b/packages/SystemUI/src/com/android/systemui/communal/widgets/SmartspaceAppWidgetHostView.kt
new file mode 100644
index 0000000..7f11463
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/communal/widgets/SmartspaceAppWidgetHostView.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.communal.widgets
+
+import android.appwidget.AppWidgetHostView
+import android.appwidget.AppWidgetProviderInfo
+import android.content.Context
+import com.android.systemui.animation.LaunchableView
+import com.android.systemui.animation.LaunchableViewDelegate
+
+/** AppWidgetHostView that displays in communal hub to show smartspace content. */
+class SmartspaceAppWidgetHostView(context: Context) : AppWidgetHostView(context), LaunchableView {
+ private val launchableViewDelegate =
+ LaunchableViewDelegate(
+ this,
+ superSetVisibility = { super.setVisibility(it) },
+ )
+
+ override fun setAppWidget(appWidgetId: Int, info: AppWidgetProviderInfo?) {
+ super.setAppWidget(appWidgetId, info)
+ setPadding(0, 0, 0, 0)
+ }
+
+ override fun getRemoteContextEnsuringCorrectCachedApkPath(): Context? {
+ // Silence errors
+ return null
+ }
+
+ override fun setShouldBlockVisibilityChanges(block: Boolean) =
+ launchableViewDelegate.setShouldBlockVisibilityChanges(block)
+
+ override fun setVisibility(visibility: Int) = launchableViewDelegate.setVisibility(visibility)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/widgets/WidgetInteractionHandler.kt b/packages/SystemUI/src/com/android/systemui/communal/widgets/WidgetInteractionHandler.kt
index 51a3a6d..e88a8b5 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/widgets/WidgetInteractionHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/widgets/WidgetInteractionHandler.kt
@@ -18,6 +18,7 @@
import android.app.ActivityOptions
import android.app.PendingIntent
+import android.appwidget.AppWidgetHostView
import android.content.Intent
import android.util.Pair
import android.view.View
@@ -26,9 +27,11 @@
import androidx.core.util.component2
import com.android.systemui.animation.ActivityTransitionAnimator
import com.android.systemui.common.ui.view.getNearestParent
+import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.plugins.ActivityStarter
import javax.inject.Inject
+@SysUISingleton
class WidgetInteractionHandler
@Inject
constructor(
@@ -55,7 +58,7 @@
pendingIntent: PendingIntent,
launchOptions: Pair<Intent, ActivityOptions>,
): Boolean {
- val hostView = view.getNearestParent<CommunalAppWidgetHostView>()
+ val hostView = view.getNearestParent<AppWidgetHostView>()
val animationController = hostView?.let(ActivityTransitionAnimator.Controller::fromView)
val (fillInIntent, activityOptions) = launchOptions
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/CommonSystemUIUnfoldModule.kt b/packages/SystemUI/src/com/android/systemui/dagger/CommonSystemUIUnfoldModule.kt
new file mode 100644
index 0000000..a91ce16
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/dagger/CommonSystemUIUnfoldModule.kt
@@ -0,0 +1,53 @@
+/*
+ * 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.dagger
+
+import com.android.systemui.unfold.SysUIUnfoldComponent
+import com.android.systemui.unfold.SysUIUnfoldModule.BoundFromSysUiUnfoldModule
+import dagger.BindsOptionalOf
+import dagger.Module
+import dagger.Provides
+import java.util.Optional
+import kotlin.jvm.optionals.getOrElse
+
+
+/**
+ * Module for foldable-related classes that is available in all SystemUI variants.
+ * Provides `Optional<SysUIUnfoldComponent>` which is present when the device is a foldable
+ * device that has fold/unfold animation enabled.
+ */
+@Module
+abstract class CommonSystemUIUnfoldModule {
+
+ /* Note this will be injected as @BoundFromSysUiUnfoldModule Optional<Optional<...>> */
+ @BindsOptionalOf
+ @BoundFromSysUiUnfoldModule
+ abstract fun optionalSysUiUnfoldComponent(): Optional<SysUIUnfoldComponent>
+
+ companion object {
+ @Provides
+ @SysUISingleton
+ fun sysUiUnfoldComponent(
+ /**
+ * This will be empty when [com.android.systemui.unfold.SysUIUnfoldModule] is not part
+ * of the graph, and contain the optional when it is.
+ */
+ @BoundFromSysUiUnfoldModule
+ optionalOfOptional: Optional<Optional<SysUIUnfoldComponent>>
+ ): Optional<SysUIUnfoldComponent> = optionalOfOptional.getOrElse { Optional.empty() }
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSysUIComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSysUIComponent.java
index a431a59..b71af69 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSysUIComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSysUIComponent.java
@@ -19,6 +19,7 @@
import com.android.systemui.keyguard.CustomizationProvider;
import com.android.systemui.statusbar.NotificationInsetsModule;
import com.android.systemui.statusbar.QsFrameTranslateModule;
+import com.android.systemui.unfold.SysUIUnfoldModule;
import dagger.Subcomponent;
@@ -34,6 +35,7 @@
SystemUIBinder.class,
SystemUIModule.class,
SystemUICoreStartableModule.class,
+ SysUIUnfoldModule.class,
ReferenceSystemUIModule.class})
public interface ReferenceSysUIComponent extends SysUIComponent {
@@ -51,3 +53,4 @@
*/
void inject(CustomizationProvider customizationProvider);
}
+
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index 2ebb94f..a7ff3c3 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -143,7 +143,6 @@
import com.android.systemui.telephony.data.repository.TelephonyRepositoryModule;
import com.android.systemui.temporarydisplay.dagger.TemporaryDisplayModule;
import com.android.systemui.tuner.dagger.TunerModule;
-import com.android.systemui.unfold.SysUIUnfoldModule;
import com.android.systemui.user.UserModule;
import com.android.systemui.user.domain.UserDomainLayerModule;
import com.android.systemui.util.EventLogModule;
@@ -254,7 +253,7 @@
SystemPropertiesFlagsModule.class,
SysUIConcurrencyModule.class,
SysUICoroutinesModule.class,
- SysUIUnfoldModule.class,
+ CommonSystemUIUnfoldModule.class,
TelephonyRepositoryModule.class,
TemporaryDisplayModule.class,
TunerModule.class,
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt
index f860893..3294c81 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt
@@ -27,11 +27,13 @@
import androidx.lifecycle.repeatOnLifecycle
import com.android.app.animation.Interpolators
import com.android.dream.lowlight.util.TruncatedInterpolator
+import com.android.systemui.ambient.statusbar.ui.AmbientStatusBarViewController
import com.android.systemui.complication.ComplicationHostViewController
import com.android.systemui.complication.ComplicationLayoutParams
import com.android.systemui.complication.ComplicationLayoutParams.POSITION_BOTTOM
import com.android.systemui.complication.ComplicationLayoutParams.POSITION_TOP
import com.android.systemui.complication.ComplicationLayoutParams.Position
+import com.android.systemui.dreams.dagger.DreamOverlayComponent.DreamOverlayScope
import com.android.systemui.dreams.dagger.DreamOverlayModule
import com.android.systemui.dreams.ui.viewmodel.DreamViewModel
import com.android.systemui.lifecycle.repeatWhenAttached
@@ -45,12 +47,13 @@
import kotlinx.coroutines.launch
/** Controller for dream overlay animations. */
+@DreamOverlayScope
class DreamOverlayAnimationsController
@Inject
constructor(
private val mBlurUtils: BlurUtils,
private val mComplicationHostViewController: ComplicationHostViewController,
- private val mStatusBarViewController: DreamOverlayStatusBarViewController,
+ private val mStatusBarViewController: AmbientStatusBarViewController,
private val mOverlayStateController: DreamOverlayStateController,
@Named(DreamOverlayModule.DREAM_BLUR_RADIUS) private val mDreamBlurRadius: Int,
private val dreamViewModel: DreamViewModel,
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
index 1e725eb..245def8 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
@@ -40,6 +40,7 @@
import com.android.app.animation.Interpolators;
import com.android.dream.lowlight.LowLightTransitionCoordinator;
+import com.android.systemui.ambient.statusbar.ui.AmbientStatusBarViewController;
import com.android.systemui.ambient.touch.scrim.BouncerlessScrimController;
import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerCallbackInteractor;
import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerCallbackInteractor.PrimaryBouncerExpansionCallback;
@@ -55,6 +56,7 @@
import com.android.systemui.shade.ShadeExpansionChangeEvent;
import com.android.systemui.shade.domain.interactor.ShadeInteractor;
import com.android.systemui.statusbar.BlurUtils;
+import com.android.systemui.touch.TouchInsetManager;
import com.android.systemui.util.ViewController;
import kotlinx.coroutines.CoroutineDispatcher;
@@ -72,10 +74,12 @@
public class DreamOverlayContainerViewController extends
ViewController<DreamOverlayContainerView> implements
LowLightTransitionCoordinator.LowLightEnterListener {
- private final DreamOverlayStatusBarViewController mStatusBarViewController;
+ private final AmbientStatusBarViewController mStatusBarViewController;
+ private final TouchInsetManager.TouchInsetSession mTouchInsetSession;
private final BlurUtils mBlurUtils;
private final DreamOverlayAnimationsController mDreamOverlayAnimationsController;
private final DreamOverlayStateController mStateController;
+
private final LowLightTransitionCoordinator mLowLightTransitionCoordinator;
private final KeyguardTransitionInteractor mKeyguardTransitionInteractor;
private final ShadeInteractor mShadeInteractor;
@@ -188,8 +192,9 @@
ComplicationHostViewController complicationHostViewController,
@Named(DreamOverlayModule.DREAM_OVERLAY_CONTENT_VIEW) ViewGroup contentView,
@Named(DreamOverlayModule.HUB_GESTURE_INDICATOR_VIEW) View hubGestureIndicatorView,
- DreamOverlayStatusBarViewController statusBarViewController,
+ AmbientStatusBarViewController statusBarViewController,
LowLightTransitionCoordinator lowLightTransitionCoordinator,
+ TouchInsetManager.TouchInsetSession touchInsetSession,
BlurUtils blurUtils,
@Main Handler handler,
@Background CoroutineDispatcher backgroundDispatcher,
@@ -209,6 +214,7 @@
super(containerView);
mDreamOverlayContentView = contentView;
mStatusBarViewController = statusBarViewController;
+ mTouchInsetSession = touchInsetSession;
mBlurUtils = blurUtils;
mDreamOverlayAnimationsController = animationsController;
mStateController = stateController;
@@ -294,6 +300,7 @@
mHandler.removeCallbacksAndMessages(null);
mPrimaryBouncerCallbackInteractor.removeBouncerExpansionCallback(mBouncerExpansionCallback);
mBouncerlessScrimController.removeCallback(mBouncerlessExpansionCallback);
+ mTouchInsetSession.clear();
mDreamOverlayAnimationsController.cancelAnimations();
}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayDotImageView.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayDotImageView.java
index 409b196..0833518 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayDotImageView.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayDotImageView.java
@@ -31,12 +31,13 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import com.android.systemui.ambient.statusbar.ui.AmbientStatusBarView;
import com.android.systemui.res.R;
import com.android.systemui.statusbar.AlphaOptimizedImageView;
/**
* An {@link AlphaOptimizedImageView} that is responsible for rendering a dot. Used by
- * {@link DreamOverlayStatusBarView}.
+ * {@link AmbientStatusBarView}.
*/
public class DreamOverlayDotImageView extends AlphaOptimizedImageView {
private final @ColorInt int mDotColor;
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayModule.java b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayModule.java
index 789b7f8..76fcabd 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayModule.java
@@ -25,9 +25,11 @@
import androidx.lifecycle.LifecycleOwner;
import com.android.internal.util.Preconditions;
+import com.android.systemui.ambient.statusbar.dagger.AmbientStatusBarComponent;
+import com.android.systemui.ambient.statusbar.ui.AmbientStatusBarView;
+import com.android.systemui.ambient.statusbar.ui.AmbientStatusBarViewController;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dreams.DreamOverlayContainerView;
-import com.android.systemui.dreams.DreamOverlayStatusBarView;
import com.android.systemui.res.R;
import com.android.systemui.touch.TouchInsetManager;
@@ -60,7 +62,7 @@
public static DreamOverlayContainerView providesDreamOverlayContainerView(
LayoutInflater layoutInflater) {
return Preconditions.checkNotNull((DreamOverlayContainerView)
- layoutInflater.inflate(R.layout.dream_overlay_container, null),
+ layoutInflater.inflate(R.layout.dream_overlay_container, null),
"R.layout.dream_layout_container could not be properly inflated");
}
@@ -95,13 +97,23 @@
/** */
@Provides
@DreamOverlayComponent.DreamOverlayScope
- public static DreamOverlayStatusBarView providesDreamOverlayStatusBarView(
+ public static AmbientStatusBarView providesDreamOverlayStatusBarView(
DreamOverlayContainerView view) {
return Preconditions.checkNotNull(view.findViewById(R.id.dream_overlay_status_bar),
"R.id.status_bar must not be null");
}
- /** */
+ /**
+ * Provides the view controller for the {@link AmbientStatusBarView}
+ */
+ @Provides
+ @DreamOverlayComponent.DreamOverlayScope
+ public static AmbientStatusBarViewController providesStatusBarViewController(
+ AmbientStatusBarView view, AmbientStatusBarComponent.Factory factory) {
+ return factory.create(view).getController();
+ }
+
+ /** */
@Provides
@DreamOverlayComponent.DreamOverlayScope
@Named(MAX_BURN_IN_OFFSET)
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 ea8d7d7..be4c903 100644
--- a/packages/SystemUI/src/com/android/systemui/haptics/qs/QSLongPressEffect.kt
+++ b/packages/SystemUI/src/com/android/systemui/haptics/qs/QSLongPressEffect.kt
@@ -17,21 +17,19 @@
package com.android.systemui.haptics.qs
import android.os.VibrationEffect
-import android.view.View
import androidx.annotation.VisibleForTesting
-import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
+import com.android.systemui.animation.Expandable
+import com.android.systemui.plugins.qs.QSTile
import com.android.systemui.statusbar.VibratorHelper
+import com.android.systemui.statusbar.policy.KeyguardStateController
import javax.inject.Inject
-import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.combine
/**
* A class that handles the long press visuo-haptic effect for a QS tile.
*
- * The class is also a [View.OnTouchListener] to handle the touch events, clicks and long-press
- * gestures of the tile. The class also provides a [State] tha can be used to determine the current
- * state of the long press effect.
+ * The class can contain references to a [QSTile] and an [Expandable] to perform clicks and
+ * long-clicks on the tile. The class also provides a [State] tha can be used to determine the
+ * current state of the long press effect.
*
* @property[vibratorHelper] The [VibratorHelper] to deliver haptic effects.
* @property[effectDuration] The duration of the effect in ms.
@@ -41,7 +39,7 @@
@Inject
constructor(
private val vibratorHelper: VibratorHelper?,
- keyguardInteractor: KeyguardInteractor,
+ private val keyguardStateController: KeyguardStateController,
) {
var effectDuration = 0
@@ -51,19 +49,12 @@
var state = State.IDLE
private set
- /** Flow for view control and action */
- private val _postedActionType = MutableStateFlow<ActionType?>(null)
- val actionType: Flow<ActionType?> =
- combine(
- _postedActionType,
- keyguardInteractor.isKeyguardDismissible,
- ) { action, isDismissible ->
- if (!isDismissible && action == ActionType.LONG_PRESS) {
- ActionType.RESET_AND_LONG_PRESS
- } else {
- action
- }
- }
+ /** Callback object for effect actions */
+ var callback: Callback? = null
+
+ /** The [QSTile] and [Expandable] used to perform a long-click and click actions */
+ var qsTile: QSTile? = null
+ var expandable: Expandable? = null
/** Haptic effects */
private val durations =
@@ -106,33 +97,24 @@
State.IDLE -> {
setState(State.TIMEOUT_WAIT)
}
- State.RUNNING_BACKWARDS -> _postedActionType.value = ActionType.CANCEL_ANIMATOR
+ State.RUNNING_BACKWARDS -> callback?.onCancelAnimator()
else -> {}
}
}
fun handleActionUp() {
- when (state) {
- State.TIMEOUT_WAIT -> {
- _postedActionType.value = ActionType.CLICK
- setState(State.IDLE)
- }
- State.RUNNING_FORWARD -> {
- _postedActionType.value = ActionType.REVERSE_ANIMATOR
- setState(State.RUNNING_BACKWARDS)
- }
- else -> {}
+ if (state == State.RUNNING_FORWARD) {
+ setState(State.RUNNING_BACKWARDS)
+ callback?.onReverseAnimator()
}
}
fun handleActionCancel() {
when (state) {
- State.TIMEOUT_WAIT -> {
- setState(State.IDLE)
- }
+ State.TIMEOUT_WAIT -> setState(State.IDLE)
State.RUNNING_FORWARD -> {
- _postedActionType.value = ActionType.REVERSE_ANIMATOR
setState(State.RUNNING_BACKWARDS)
+ callback?.onReverseAnimator()
}
else -> {}
}
@@ -146,8 +128,15 @@
/** This function is called both when an animator completes or gets cancelled */
fun handleAnimationComplete() {
if (state == State.RUNNING_FORWARD) {
+ setState(State.IDLE)
vibrate(snapEffect)
- _postedActionType.value = ActionType.LONG_PRESS
+ if (keyguardStateController.isUnlocked) {
+ callback?.onPrepareForLaunch()
+ qsTile?.longClick(expandable)
+ } else {
+ callback?.onResetProperties()
+ qsTile?.longClick(expandable)
+ }
}
if (state != State.TIMEOUT_WAIT) {
// This will happen if the animator did not finish by being cancelled
@@ -161,12 +150,19 @@
fun handleTimeoutComplete() {
if (state == State.TIMEOUT_WAIT) {
- _postedActionType.value = ActionType.START_ANIMATOR
+ callback?.onStartAnimator()
}
}
- fun clearActionType() {
- _postedActionType.value = null
+ fun onTileClick(): Boolean {
+ if (state == State.TIMEOUT_WAIT) {
+ setState(State.IDLE)
+ qsTile?.let {
+ it.click(expandable)
+ return true
+ }
+ }
+ return false
}
/**
@@ -200,13 +196,22 @@
RUNNING_BACKWARDS, /* The effect was interrupted and is now running backwards */
}
- /* A type of action to perform on the view depending on the effect's state and logic */
- enum class ActionType {
- CLICK,
- LONG_PRESS,
- RESET_AND_LONG_PRESS,
- START_ANIMATOR,
- REVERSE_ANIMATOR,
- CANCEL_ANIMATOR,
+ /** Callbacks to notify view and animator actions */
+ interface Callback {
+
+ /** Prepare for an activity launch */
+ fun onPrepareForLaunch()
+
+ /** Reset the tile visual properties */
+ fun onResetProperties()
+
+ /** Start the effect animator */
+ fun onStartAnimator()
+
+ /** Reverse the effect animator */
+ fun onReverseAnimator()
+
+ /** Cancel the effect animator */
+ fun onCancelAnimator()
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/haptics/qs/QSLongPressEffectViewBinder.kt b/packages/SystemUI/src/com/android/systemui/haptics/qs/QSLongPressEffectViewBinder.kt
deleted file mode 100644
index 4875f48..0000000
--- a/packages/SystemUI/src/com/android/systemui/haptics/qs/QSLongPressEffectViewBinder.kt
+++ /dev/null
@@ -1,127 +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.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
-import com.android.systemui.lifecycle.repeatWhenAttached
-import com.android.systemui.qs.tileimpl.QSTileViewImpl
-import kotlinx.coroutines.DisposableHandle
-import kotlinx.coroutines.flow.filterNotNull
-
-object QSLongPressEffectViewBinder {
-
- fun bind(
- tile: QSTileViewImpl,
- qsLongPressEffect: QSLongPressEffect?,
- tileSpec: String?,
- ): DisposableHandle? {
- if (qsLongPressEffect == null) return null
-
- // Set the touch listener as the long-press effect
- setTouchListener(tile, qsLongPressEffect)
-
- return tile.repeatWhenAttached {
- repeatOnLifecycle(Lifecycle.State.CREATED) {
- // Action to perform
- launch({ "${tileSpec ?: "unknownTileSpec"}#LongPressEffect#action" }) {
- var effectAnimator: ValueAnimator? = null
-
- qsLongPressEffect.actionType.filterNotNull().collect { action ->
- when (action) {
- QSLongPressEffect.ActionType.CLICK -> {
- tile.performClick()
- qsLongPressEffect.clearActionType()
- }
- QSLongPressEffect.ActionType.LONG_PRESS -> {
- tile.prepareForLaunch()
- tile.performLongClick()
- qsLongPressEffect.clearActionType()
- }
- QSLongPressEffect.ActionType.RESET_AND_LONG_PRESS -> {
- tile.resetLongPressEffectProperties()
- tile.performLongClick()
- qsLongPressEffect.clearActionType()
- }
- QSLongPressEffect.ActionType.START_ANIMATOR -> {
- if (effectAnimator?.isRunning != true) {
- 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() }
- start()
- }
- }
- }
- QSLongPressEffect.ActionType.REVERSE_ANIMATOR -> {
- effectAnimator?.let {
- val pausedProgress = it.animatedFraction
- qsLongPressEffect.playReverseHaptics(pausedProgress)
- it.reverse()
- }
- }
- QSLongPressEffect.ActionType.CANCEL_ANIMATOR -> {
- tile.resetLongPressEffectProperties()
- effectAnimator?.cancel()
- }
- }
- }
- }
- }
- }
- }
-
- @SuppressLint("ClickableViewAccessibility")
- private fun setTouchListener(tile: QSTileViewImpl, longPressEffect: QSLongPressEffect?) {
- tile.setOnTouchListener { _, event ->
- when (event.actionMasked) {
- MotionEvent.ACTION_DOWN -> {
- tile.postDelayed(
- { longPressEffect?.handleTimeoutComplete() },
- ViewConfiguration.getTapTimeout().toLong(),
- )
- longPressEffect?.handleActionDown()
- }
- MotionEvent.ACTION_UP -> longPressEffect?.handleActionUp()
- MotionEvent.ACTION_CANCEL -> longPressEffect?.handleActionCancel()
- }
- true
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/WindowManagerLockscreenVisibilityManager.kt b/packages/SystemUI/src/com/android/systemui/keyguard/WindowManagerLockscreenVisibilityManager.kt
index 1b342ed..180afb2 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/WindowManagerLockscreenVisibilityManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/WindowManagerLockscreenVisibilityManager.kt
@@ -142,15 +142,17 @@
nonApps: Array<RemoteAnimationTarget>,
finishedCallback: IRemoteAnimationFinishedCallback
) {
- if (apps.isNotEmpty()) {
- // Ensure that we've started a dismiss keyguard transition. WindowManager can start the
- // going away animation on its own, if an activity launches and then requests dismissing
- // the keyguard. In this case, this is the first and only signal we'll receive to start
- // a transition to GONE.
- keyguardTransitionInteractor.startDismissKeyguardTransition(
- reason = "Going away remote animation started"
- )
+ // Ensure that we've started a dismiss keyguard transition. WindowManager can start the
+ // going away animation on its own, if an activity launches and then requests dismissing the
+ // keyguard. In this case, this is the first and only signal we'll receive to start
+ // a transition to GONE. This transition needs to start even if we're not provided an app
+ // animation target - it's possible the app is destroyed on creation, etc. but we'll still
+ // be unlocking.
+ keyguardTransitionInteractor.startDismissKeyguardTransition(
+ reason = "Going away remote animation started"
+ )
+ if (apps.isNotEmpty()) {
goingAwayRemoteAnimationFinishedCallback = finishedCallback
keyguardSurfaceBehindAnimator.applyParamsToSurface(apps[0])
} else {
@@ -183,25 +185,11 @@
/**
* Sets the lockscreen state WM-side by calling ATMS#setLockScreenShown.
*
- * [lockscreenShowing] defaults to true, since it's only ever null during the boot sequence,
- * when we haven't yet called ATMS#setLockScreenShown. Typically,
- * setWmLockscreenState(lockscreenShowing = true) is called early in the boot sequence, before
- * setWmLockscreenState(aodVisible = true), so we don't expect to need to use this default, but
- * if so, true should be the right choice.
+ * If [lockscreenShowing] is null, it means we don't know if the lockscreen is showing yet. This
+ * will be decided by the [KeyguardTransitionBootInteractor] shortly.
*/
private fun setWmLockscreenState(
- lockscreenShowing: Boolean =
- this.isLockscreenShowing
- ?: true.also {
- Log.d(
- TAG,
- "Using isLockscreenShowing=true default in setWmLockscreenState, " +
- "because setAodVisible was called before the first " +
- "setLockscreenShown call during boot. This is not typical, but is " +
- "theoretically possible. If you're investigating the lockscreen " +
- "showing unexpectedly, start here."
- )
- },
+ lockscreenShowing: Boolean? = this.isLockscreenShowing,
aodVisible: Boolean = this.isAodVisible
) {
Log.d(
@@ -211,10 +199,27 @@
"aodVisible=$aodVisible)."
)
+ if (lockscreenShowing == null) {
+ Log.d(
+ TAG,
+ "isAodVisible=$aodVisible, but lockscreenShowing=null. Waiting for" +
+ "non-null lockscreenShowing before calling ATMS#setLockScreenShown, which" +
+ "will happen once KeyguardTransitionBootInteractor starts the boot transition."
+ )
+ this.isAodVisible = aodVisible
+ return
+ }
+
if (this.isLockscreenShowing == lockscreenShowing && this.isAodVisible == aodVisible) {
return
}
+ Log.d(
+ TAG,
+ "ATMS#setLockScreenShown(" +
+ "isLockscreenShowing=$lockscreenShowing, " +
+ "aodVisible=$aodVisible)."
+ )
activityTaskManagerService.setLockScreenShown(lockscreenShowing, aodVisible)
this.isLockscreenShowing = lockscreenShowing
this.isAodVisible = aodVisible
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt
index 8ec460a..1b201ce 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt
@@ -20,6 +20,7 @@
import android.animation.ValueAnimator
import android.animation.ValueAnimator.AnimatorUpdateListener
import android.annotation.FloatRange
+import android.annotation.SuppressLint
import android.os.Trace
import android.util.Log
import com.android.app.tracing.coroutines.withContext
@@ -117,10 +118,11 @@
constructor(
@Main val mainDispatcher: CoroutineDispatcher,
) : KeyguardTransitionRepository {
- /*
- * Each transition between [KeyguardState]s will have an associated Flow.
- * In order to collect these events, clients should call [transition].
+ /**
+ * Each transition between [KeyguardState]s will have an associated Flow. In order to collect
+ * these events, clients should call [transition].
*/
+ @SuppressLint("SharedFlowCreation")
private val _transitions =
MutableSharedFlow<TransitionStep>(
replay = 2,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt
index 756c6c2..14eb972 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt
@@ -24,9 +24,12 @@
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.keyguard.KeyguardWmStateRefactor
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
+import com.android.systemui.keyguard.shared.model.Edge
import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.power.domain.interactor.PowerInteractor
import com.android.systemui.scene.shared.flag.SceneContainerFlag
+import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.util.kotlin.Utils.Companion.sample as sampleCombine
import com.android.wm.shell.animation.Interpolators
import javax.inject.Inject
@@ -36,7 +39,6 @@
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.emptyFlow
import kotlinx.coroutines.flow.filter
@@ -81,17 +83,16 @@
}
val surfaceBehindVisibility: Flow<Boolean?> =
- combine(
- transitionInteractor.startedKeyguardTransitionStep,
- transitionInteractor.transitionStepsFromState(KeyguardState.ALTERNATE_BOUNCER)
- ) { startedStep, fromBouncerStep ->
- if (startedStep.to != KeyguardState.GONE) {
- return@combine null
- }
-
+ transitionInteractor
+ .transition(
+ edge = Edge.create(from = KeyguardState.ALTERNATE_BOUNCER, to = Scenes.Gone),
+ edgeWithoutSceneContainer =
+ Edge.create(from = KeyguardState.ALTERNATE_BOUNCER, to = KeyguardState.GONE)
+ )
+ .map<TransitionStep, Boolean?> {
// The alt bouncer is pretty fast to hide, so start the surface behind animation
// around 30%.
- fromBouncerStep.value > 0.3f
+ it.value > 0.3f
}
.onStart {
// Default to null ("don't care, use a reasonable default").
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
index 8cab3cd..f30eef0 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
@@ -24,16 +24,18 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
-import com.android.systemui.flags.FeatureFlags
import com.android.systemui.keyguard.KeyguardWmStateRefactor
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
+import com.android.systemui.keyguard.shared.model.Edge
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.StatusBarState.KEYGUARD
import com.android.systemui.keyguard.shared.model.TransitionInfo
import com.android.systemui.keyguard.shared.model.TransitionModeOnCanceled
import com.android.systemui.keyguard.shared.model.TransitionState
+import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.power.domain.interactor.PowerInteractor
import com.android.systemui.scene.shared.flag.SceneContainerFlag
+import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.shade.data.repository.ShadeRepository
import com.android.systemui.util.kotlin.Utils.Companion.sample as sampleCombine
import java.util.UUID
@@ -59,7 +61,6 @@
@Background bgDispatcher: CoroutineDispatcher,
@Main mainDispatcher: CoroutineDispatcher,
keyguardInteractor: KeyguardInteractor,
- private val flags: FeatureFlags,
private val shadeRepository: ShadeRepository,
powerInteractor: PowerInteractor,
private val glanceableHubTransitions: GlanceableHubTransitions,
@@ -97,14 +98,13 @@
* LOCKSCREEN is running.
*/
val surfaceBehindVisibility: Flow<Boolean?> =
- transitionInteractor.startedKeyguardTransitionStep
- .map { startedStep ->
- if (startedStep.to != KeyguardState.GONE) {
- // LOCKSCREEN to anything but GONE does not require any special surface
- // visibility handling.
- return@map null
- }
-
+ transitionInteractor
+ .transition(
+ edge = Edge.create(from = KeyguardState.LOCKSCREEN, to = Scenes.Gone),
+ edgeWithoutSceneContainer =
+ Edge.create(from = KeyguardState.LOCKSCREEN, to = KeyguardState.GONE)
+ )
+ .map<TransitionStep, Boolean?> {
true // Make the surface visible during LS -> GONE transitions.
}
.onStart {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt
index 8cf4b53..f8208b3 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt
@@ -22,11 +22,12 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
-import com.android.systemui.flags.FeatureFlags
import com.android.systemui.keyguard.KeyguardWmStateRefactor
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
+import com.android.systemui.keyguard.shared.model.Edge
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionModeOnCanceled
+import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.power.domain.interactor.PowerInteractor
import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.user.domain.interactor.SelectedUserInteractor
@@ -38,8 +39,9 @@
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.launch
@@ -54,7 +56,6 @@
@Main mainDispatcher: CoroutineDispatcher,
keyguardInteractor: KeyguardInteractor,
private val communalInteractor: CommunalInteractor,
- private val flags: FeatureFlags,
private val keyguardSecurityModel: KeyguardSecurityModel,
private val selectedUserInteractor: SelectedUserInteractor,
powerInteractor: PowerInteractor,
@@ -79,21 +80,25 @@
}
val surfaceBehindVisibility: Flow<Boolean?> =
- combine(
- transitionInteractor.startedKeyguardTransitionStep,
- transitionInteractor.transitionStepsFromState(KeyguardState.PRIMARY_BOUNCER)
- ) { startedStep, fromBouncerStep ->
- if (startedStep.to != KeyguardState.GONE) {
- return@combine null
+ if (SceneContainerFlag.isEnabled) {
+ // The edge Scenes.Bouncer <-> Scenes.Gone is handled by STL
+ flowOf(null)
+ } else {
+ transitionInteractor
+ .transition(
+ edge = Edge.INVALID,
+ edgeWithoutSceneContainer =
+ Edge.create(from = KeyguardState.PRIMARY_BOUNCER, to = KeyguardState.GONE)
+ )
+ .map<TransitionStep, Boolean?> {
+ it.value > TO_GONE_SURFACE_BEHIND_VISIBLE_THRESHOLD
}
-
- fromBouncerStep.value > TO_GONE_SURFACE_BEHIND_VISIBLE_THRESHOLD
- }
- .onStart {
- // Default to null ("don't care, use a reasonable default").
- emit(null)
- }
- .distinctUntilChanged()
+ .onStart {
+ // Default to null ("don't care, use a reasonable default").
+ emit(null)
+ }
+ .distinctUntilChanged()
+ }
fun dismissPrimaryBouncer() {
scope.launch { startTransitionTo(KeyguardState.GONE) }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
index 73835a3c..48660f2 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
@@ -50,7 +50,7 @@
import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.statusbar.notification.NotificationUtils.interpolate
import com.android.systemui.statusbar.notification.stack.domain.interactor.SharedNotificationContainerInteractor
-import com.android.systemui.util.kotlin.Utils.Companion.sample as sampleCombine
+import com.android.systemui.util.kotlin.Utils.Companion.sampleFilter
import com.android.systemui.util.kotlin.pairwise
import com.android.systemui.util.kotlin.sample
import javax.inject.Inject
@@ -77,6 +77,7 @@
import kotlinx.coroutines.flow.merge
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.flow.stateIn
+import com.android.systemui.util.kotlin.Utils.Companion.sample as sampleCombine
/**
* Encapsulates business-logic related to the keyguard but not to a more specific part within it.
@@ -91,7 +92,7 @@
bouncerRepository: KeyguardBouncerRepository,
configurationInteractor: ConfigurationInteractor,
shadeRepository: ShadeRepository,
- keyguardTransitionInteractor: KeyguardTransitionInteractor,
+ private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
sceneInteractorProvider: Provider<SceneInteractor>,
private val fromGoneTransitionInteractor: Provider<FromGoneTransitionInteractor>,
private val fromLockscreenTransitionInteractor: Provider<FromLockscreenTransitionInteractor>,
@@ -248,21 +249,17 @@
val isKeyguardGoingAway: Flow<Boolean> = repository.isKeyguardGoingAway
/** Keyguard can be clipped at the top as the shade is dragged */
- val topClippingBounds: Flow<Int?> =
- combineTransform(
- configurationInteractor.onAnyConfigurationChange,
+ val topClippingBounds: Flow<Int?> by lazy {
+ repository.topClippingBounds
+ .sampleFilter(
keyguardTransitionInteractor
- .transitionValue(GONE)
- .map { it == 1f }
- .onStart { emit(false) }
- .distinctUntilChanged(),
- repository.topClippingBounds
- ) { _, isGone, topClippingBounds ->
- if (!isGone) {
- emit(topClippingBounds)
- }
+ .transitionValue(scene = Scenes.Gone, stateWithoutSceneContainer = GONE)
+ .onStart { emit(0f) }
+ ) { goneValue ->
+ goneValue != 1f
}
.distinctUntilChanged()
+ }
/** Last point that [KeyguardRootView] view was tapped */
val lastRootViewTapPosition: Flow<Point?> = repository.lastRootViewTapPosition.asStateFlow()
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
index 2766b71..37272dc 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
@@ -223,6 +223,17 @@
}
}
+ fun transitionValue(
+ scene: SceneKey,
+ stateWithoutSceneContainer: KeyguardState,
+ ): Flow<Float> {
+ return if (SceneContainerFlag.isEnabled) {
+ sceneInteractor.get().transitionProgress(scene)
+ } else {
+ transitionValue(stateWithoutSceneContainer)
+ }
+ }
+
/**
* The amount of transition into or out of the given [KeyguardState].
*
@@ -232,26 +243,13 @@
fun transitionValue(
state: KeyguardState,
): Flow<Float> {
+ if (SceneContainerFlag.isEnabled && state != state.mapToSceneContainerState()) {
+ Log.e(TAG, "SceneContainer is enabled but a deprecated state $state is used.")
+ return transitionValue(state.mapToSceneContainerScene()!!, state)
+ }
return getTransitionValueFlow(state)
}
- /**
- * AOD<->* transition information, mapped to dozeAmount range of AOD (1f) <->
- * * (0f).
- */
- @SuppressLint("SharedFlowCreation")
- val dozeAmountTransition: Flow<TransitionStep> =
- repository.transitions
- .filter { step -> step.from == AOD || step.to == AOD }
- .map { step ->
- if (step.from == AOD) {
- step.copy(value = 1 - step.value)
- } else {
- step
- }
- }
- .shareIn(scope, SharingStarted.Eagerly, replay = 1)
-
/** The last [TransitionStep] with a [TransitionState] of STARTED */
val startedKeyguardTransitionStep: Flow<TransitionStep> =
repository.transitions.filter { step -> step.transitionState == TransitionState.STARTED }
@@ -267,8 +265,6 @@
.map { step -> step.to }
.shareIn(scope, SharingStarted.Eagerly, replay = 1)
- val currentTransitionInfo: StateFlow<TransitionInfo> = repository.currentTransitionInfoInternal
-
/** The from state of the last [TransitionState.STARTED] transition. */
// TODO: is it performant to have several SharedFlows side by side instead of one?
@SuppressLint("SharedFlowCreation")
@@ -415,14 +411,6 @@
/** Whether we've currently STARTED a transition and haven't yet FINISHED it. */
val isInTransitionToAnyState = isInTransitionWhere({ true }, { true })
- fun transitionStepsFromState(fromState: KeyguardState): Flow<TransitionStep> {
- return transition(Edge.create(from = fromState, to = null))
- }
-
- fun transitionStepsToState(toState: KeyguardState): Flow<TransitionStep> {
- return transition(Edge.create(from = null, to = toState))
- }
-
/**
* Called to start a transition that will ultimately dismiss the keyguard from the current
* state.
@@ -558,10 +546,6 @@
return currentKeyguardState.replayCache.last()
}
- fun getStartedState(): KeyguardState {
- return startedKeyguardState.replayCache.last()
- }
-
fun getStartedFromState(): KeyguardState {
return startedKeyguardFromState.replayCache.last()
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractor.kt
index 88e6602..3a43b1c 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractor.kt
@@ -229,11 +229,14 @@
val aodVisibility: Flow<Boolean> =
combine(
keyguardInteractor.isDozing,
+ keyguardInteractor.isAodAvailable,
keyguardInteractor.biometricUnlockState,
- ) { isDozing, biometricUnlockState ->
+ ) { isDozing, isAodAvailable, biometricUnlockState ->
// AOD is visible if we're dozing, unless we are wake and unlocking (where we go
// directly from AOD to unlocked while dozing).
- isDozing && !BiometricUnlockMode.isWakeAndUnlock(biometricUnlockState.mode)
+ isDozing &&
+ isAodAvailable &&
+ !BiometricUnlockMode.isWakeAndUnlock(biometricUnlockState.mode)
}
.distinctUntilChanged()
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/scenetransition/LockscreenSceneTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/scenetransition/LockscreenSceneTransitionInteractor.kt
index 3baeb76..9b3ba7d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/scenetransition/LockscreenSceneTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/scenetransition/LockscreenSceneTransitionInteractor.kt
@@ -131,7 +131,7 @@
val newTransition =
TransitionInfo(
ownerName = this::class.java.simpleName,
- from = transitionInteractor.currentTransitionInfo.value.to,
+ from = transitionInteractor.currentTransitionInfoInternal.value.to,
to = state,
animator = null,
modeOnCanceled = TransitionModeOnCanceled.REVERSE
@@ -150,7 +150,7 @@
private suspend fun handleTransition(transition: ObservableTransitionState.Transition) {
if (transition.fromScene == Scenes.Lockscreen) {
if (currentTransitionId != null) {
- val currentToState = transitionInteractor.currentTransitionInfo.value.to
+ val currentToState = transitionInteractor.currentTransitionInfoInternal.value.to
if (currentToState == UNDEFINED) {
transitionKtfTo(transitionInteractor.getStartedFromState())
}
@@ -201,7 +201,7 @@
}
private suspend fun startTransitionFromLockscreen() {
- val currentState = transitionInteractor.currentTransitionInfo.value.to
+ val currentState = transitionInteractor.currentTransitionInfoInternal.value.to
val newTransition =
TransitionInfo(
ownerName = this::class.java.simpleName,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/Edge.kt b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/Edge.kt
index c1e8d22..1306b26 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/Edge.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/Edge.kt
@@ -96,10 +96,23 @@
companion object {
private const val TAG = "Edge"
+ @JvmStatic
+ @JvmOverloads
fun create(from: KeyguardState? = null, to: KeyguardState? = null) = StateToState(from, to)
+ @JvmStatic
+ @JvmOverloads
fun create(from: KeyguardState? = null, to: SceneKey) = StateToScene(from, to)
+ @JvmStatic
+ @JvmOverloads
fun create(from: SceneKey, to: KeyguardState? = null) = SceneToState(from, to)
+
+ /**
+ * This edge is a placeholder for when an edge needs to be passed but there is no edge for
+ * this flag configuration available. Usually for Scene <-> Scene edges with scene container
+ * enabled where these edges are managed by STL separately.
+ */
+ val INVALID = StateToState(UNDEFINED, UNDEFINED)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/TransitionStep.kt b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/TransitionStep.kt
index 2b4c4af..0a8c190 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/TransitionStep.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/TransitionStep.kt
@@ -15,6 +15,9 @@
*/
package com.android.systemui.keyguard.shared.model
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.filter
+
/** This information will flow from the [KeyguardTransitionRepository] to control the UI layer */
data class TransitionStep
@JvmOverloads
@@ -39,3 +42,6 @@
return to == state && transitionState == TransitionState.FINISHED
}
}
+
+fun Flow<TransitionStep>.filterState(transitionState: TransitionState) =
+ this.filter { it.transitionState == transitionState }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/transitions/IntraBlueprintTransition.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/transitions/IntraBlueprintTransition.kt
index 39f1ebe..aa0a9d9 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/transitions/IntraBlueprintTransition.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/transitions/IntraBlueprintTransition.kt
@@ -62,7 +62,7 @@
addTransition(
clockViewModel.currentClock.value?.let { DefaultClockSteppingTransition(it) }
)
- else -> addTransition(ClockSizeTransition(config, clockViewModel, smartspaceViewModel))
+ else -> addTransition(ClockSizeTransition(config, clockViewModel))
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/transitions/ClockSizeTransition.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/transitions/ClockSizeTransition.kt
index f17dbd2..4d914c7 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/transitions/ClockSizeTransition.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/transitions/ClockSizeTransition.kt
@@ -31,8 +31,9 @@
import com.android.app.animation.Interpolators
import com.android.systemui.keyguard.ui.view.layout.blueprints.transitions.IntraBlueprintTransition
import com.android.systemui.keyguard.ui.view.layout.blueprints.transitions.IntraBlueprintTransition.Type
+import com.android.systemui.keyguard.ui.view.layout.sections.transitions.ClockSizeTransition.SmartspaceMoveTransition.Companion.STATUS_AREA_MOVE_DOWN_MILLIS
+import com.android.systemui.keyguard.ui.view.layout.sections.transitions.ClockSizeTransition.SmartspaceMoveTransition.Companion.STATUS_AREA_MOVE_UP_MILLIS
import com.android.systemui.keyguard.ui.viewmodel.KeyguardClockViewModel
-import com.android.systemui.keyguard.ui.viewmodel.KeyguardSmartspaceViewModel
import com.android.systemui.res.R
import com.android.systemui.shared.R as sharedR
import com.google.android.material.math.MathUtils
@@ -46,13 +47,12 @@
class ClockSizeTransition(
config: IntraBlueprintTransition.Config,
clockViewModel: KeyguardClockViewModel,
- smartspaceViewModel: KeyguardSmartspaceViewModel,
) : TransitionSet() {
init {
ordering = ORDERING_TOGETHER
if (config.type != Type.SmartspaceVisibility) {
- addTransition(ClockFaceOutTransition(config, clockViewModel, smartspaceViewModel))
- addTransition(ClockFaceInTransition(config, clockViewModel, smartspaceViewModel))
+ addTransition(ClockFaceOutTransition(config, clockViewModel))
+ addTransition(ClockFaceInTransition(config, clockViewModel))
}
addTransition(SmartspaceMoveTransition(config, clockViewModel))
}
@@ -60,8 +60,11 @@
abstract class VisibilityBoundsTransition() : Transition() {
abstract val captureSmartspace: Boolean
protected val TAG = this::class.simpleName!!
+
override fun captureEndValues(transition: TransitionValues) = captureValues(transition)
+
override fun captureStartValues(transition: TransitionValues) = captureValues(transition)
+
override fun getTransitionProperties(): Array<String> = TRANSITION_PROPERTIES
private fun captureValues(transition: TransitionValues) {
@@ -222,21 +225,19 @@
}
}
- class ClockFaceInTransition(
+ abstract class ClockFaceTransition(
config: IntraBlueprintTransition.Config,
val viewModel: KeyguardClockViewModel,
- val smartspaceViewModel: KeyguardSmartspaceViewModel,
) : VisibilityBoundsTransition() {
- override val captureSmartspace = !viewModel.isLargeClockVisible.value
+ protected abstract val isLargeClock: Boolean
+ protected abstract val smallClockMoveScale: Float
+ override val captureSmartspace
+ get() = !isLargeClock
- init {
- duration = CLOCK_IN_MILLIS
- startDelay = CLOCK_IN_START_DELAY_MILLIS
- interpolator = CLOCK_IN_INTERPOLATOR
-
- if (viewModel.isLargeClockVisible.value) {
+ protected fun addTargets() {
+ if (isLargeClock) {
viewModel.currentClock.value?.let {
- if (DEBUG) Log.i(TAG, "Large Clock In: ${it.largeClock.layout.views}")
+ if (DEBUG) Log.i(TAG, "Adding large clock views: ${it.largeClock.layout.views}")
it.largeClock.layout.views.forEach { addTarget(it) }
}
?: run {
@@ -244,7 +245,7 @@
addTarget(R.id.lockscreen_clock_view_large)
}
} else {
- if (DEBUG) Log.i(TAG, "Small Clock In")
+ if (DEBUG) Log.i(TAG, "Adding small clock")
addTarget(R.id.lockscreen_clock_view)
}
}
@@ -262,89 +263,59 @@
if (fromIsVis == toIsVis) return
fromBounds.set(toBounds)
- if (viewModel.isLargeClockVisible.value) {
+ if (isLargeClock) {
// Large clock shouldn't move; fromBounds already set
} else if (toSSBounds != null && fromSSBounds != null) {
// Instead of moving the small clock the full distance, we compute the distance
// smartspace will move. We then scale this to match the duration of this animation
// so that the small clock moves at the same speed as smartspace.
val ssTranslation =
- abs((toSSBounds.top - fromSSBounds.top) * SMALL_CLOCK_IN_MOVE_SCALE).toInt()
+ abs((toSSBounds.top - fromSSBounds.top) * smallClockMoveScale).toInt()
fromBounds.top = toBounds.top - ssTranslation
fromBounds.bottom = toBounds.bottom - ssTranslation
} else {
Log.e(TAG, "mutateBounds: smallClock received no smartspace bounds")
}
}
+ }
+
+ class ClockFaceInTransition(
+ config: IntraBlueprintTransition.Config,
+ viewModel: KeyguardClockViewModel,
+ ) : ClockFaceTransition(config, viewModel) {
+ override val isLargeClock = viewModel.isLargeClockVisible.value
+ override val smallClockMoveScale = CLOCK_IN_MILLIS / STATUS_AREA_MOVE_DOWN_MILLIS.toFloat()
+
+ init {
+ duration = CLOCK_IN_MILLIS
+ startDelay = CLOCK_IN_START_DELAY_MILLIS
+ interpolator = CLOCK_IN_INTERPOLATOR
+ addTargets()
+ }
companion object {
const val CLOCK_IN_MILLIS = 167L
const val CLOCK_IN_START_DELAY_MILLIS = 133L
val CLOCK_IN_INTERPOLATOR = Interpolators.LINEAR_OUT_SLOW_IN
- const val SMALL_CLOCK_IN_MOVE_SCALE =
- CLOCK_IN_MILLIS / SmartspaceMoveTransition.STATUS_AREA_MOVE_DOWN_MILLIS.toFloat()
}
}
class ClockFaceOutTransition(
config: IntraBlueprintTransition.Config,
- val viewModel: KeyguardClockViewModel,
- val smartspaceViewModel: KeyguardSmartspaceViewModel,
- ) : VisibilityBoundsTransition() {
- override val captureSmartspace = viewModel.isLargeClockVisible.value
+ viewModel: KeyguardClockViewModel,
+ ) : ClockFaceTransition(config, viewModel) {
+ override val isLargeClock = !viewModel.isLargeClockVisible.value
+ override val smallClockMoveScale = CLOCK_OUT_MILLIS / STATUS_AREA_MOVE_UP_MILLIS.toFloat()
init {
duration = CLOCK_OUT_MILLIS
interpolator = CLOCK_OUT_INTERPOLATOR
-
- if (viewModel.isLargeClockVisible.value) {
- if (DEBUG) Log.i(TAG, "Small Clock Out")
- addTarget(R.id.lockscreen_clock_view)
- } else {
- viewModel.currentClock.value?.let {
- if (DEBUG) Log.i(TAG, "Large Clock Out: ${it.largeClock.layout.views}")
- it.largeClock.layout.views.forEach { addTarget(it) }
- }
- ?: run {
- Log.e(TAG, "No large clock set, falling back")
- addTarget(R.id.lockscreen_clock_view_large)
- }
- }
- }
-
- override fun mutateBounds(
- view: View,
- fromIsVis: Boolean,
- toIsVis: Boolean,
- fromBounds: Rect,
- toBounds: Rect,
- fromSSBounds: Rect?,
- toSSBounds: Rect?
- ) {
- // Move normally if clock is not changing visibility
- if (fromIsVis == toIsVis) return
-
- toBounds.set(fromBounds)
- if (!viewModel.isLargeClockVisible.value) {
- // Large clock shouldn't move; toBounds already set
- } else if (toSSBounds != null && fromSSBounds != null) {
- // Instead of moving the small clock the full distance, we compute the distance
- // smartspace will move. We then scale this to match the duration of this animation
- // so that the small clock moves at the same speed as smartspace.
- val ssTranslation =
- abs((toSSBounds.top - fromSSBounds.top) * SMALL_CLOCK_OUT_MOVE_SCALE).toInt()
- toBounds.top = fromBounds.top - ssTranslation
- toBounds.bottom = fromBounds.bottom - ssTranslation
- } else {
- Log.e(TAG, "mutateBounds: smallClock received no smartspace bounds")
- }
+ addTargets()
}
companion object {
const val CLOCK_OUT_MILLIS = 133L
val CLOCK_OUT_INTERPOLATOR = Interpolators.LINEAR
- const val SMALL_CLOCK_OUT_MOVE_SCALE =
- CLOCK_OUT_MILLIS / SmartspaceMoveTransition.STATUS_AREA_MOVE_UP_MILLIS.toFloat()
}
}
@@ -353,15 +324,14 @@
val config: IntraBlueprintTransition.Config,
viewModel: KeyguardClockViewModel,
) : VisibilityBoundsTransition() {
+ private val isLargeClock = viewModel.isLargeClockVisible.value
override val captureSmartspace = false
init {
duration =
- if (viewModel.isLargeClockVisible.value) STATUS_AREA_MOVE_UP_MILLIS
- else STATUS_AREA_MOVE_DOWN_MILLIS
+ if (isLargeClock) STATUS_AREA_MOVE_UP_MILLIS else STATUS_AREA_MOVE_DOWN_MILLIS
interpolator = Interpolators.EMPHASIZED
addTarget(sharedR.id.date_smartspace_view)
- addTarget(sharedR.id.weather_smartspace_view)
addTarget(sharedR.id.bc_smartspace_view)
// Notifications normally and media on split shade needs to be moved
@@ -391,6 +361,6 @@
}
companion object {
- val DEBUG = true
+ val DEBUG = false
}
}
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 c05a1b7..d9a6d64 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
@@ -29,6 +29,7 @@
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
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.ui.StateToValue
import com.android.systemui.res.R
import javax.inject.Inject
@@ -111,8 +112,8 @@
params: BurnInParameters,
): Flow<BurnInModel> {
return combine(
- keyguardTransitionInteractor.dozeAmountTransition.map {
- Interpolators.FAST_OUT_SLOW_IN.getInterpolation(it.value)
+ keyguardTransitionInteractor.transitionValue(KeyguardState.AOD).map {
+ Interpolators.FAST_OUT_SLOW_IN.getInterpolation(it)
},
burnInInteractor.burnIn(
xDimenResourceId = R.dimen.burn_in_prevention_offset_x,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryForegroundViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryForegroundViewModel.kt
index 0f1f5c1..06b76b3 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryForegroundViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryForegroundViewModel.kt
@@ -52,8 +52,11 @@
udfpsOverlayInteractor: UdfpsOverlayInteractor,
) {
private val isShowingAodOrDozing: Flow<Boolean> =
- transitionInteractor.startedKeyguardState.map { keyguardState ->
- keyguardState == KeyguardState.AOD || keyguardState == KeyguardState.DOZING
+ combine(
+ transitionInteractor.startedKeyguardState,
+ transitionInteractor.transitionValue(KeyguardState.DOZING),
+ ) { startedKeyguardState, dozingTransitionValue ->
+ startedKeyguardState == KeyguardState.AOD || dozingTransitionValue == 1f
}
private fun getColor(usingBackgroundProtection: Boolean): Int {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModel.kt
index fa43ec2..92bba38 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModel.kt
@@ -264,7 +264,7 @@
accessibilityInteractor.isEnabled.flatMapLatest { touchExplorationEnabled ->
if (touchExplorationEnabled) {
combine(iconType, isInteractive) { iconType, isInteractive ->
- if (isInteractive) {
+ if (isInteractive || iconType == DeviceEntryIconView.IconType.LOCK) {
iconType.toAccessibilityHintType()
} else {
DeviceEntryIconView.AccessibilityHintType.NONE
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBlueprintViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBlueprintViewModel.kt
index 7ac03bf..c6efcfa 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBlueprintViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBlueprintViewModel.kt
@@ -130,6 +130,6 @@
companion object {
private const val TAG = "KeyguardBlueprintViewModel"
- private const val DEBUG = true
+ private const val DEBUG = false
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt
index ee52ad0..5027524 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt
@@ -203,7 +203,7 @@
combine(
communalInteractor.isIdleOnCommunal,
keyguardTransitionInteractor
- .transitionValue(GONE)
+ .transitionValue(scene = Scenes.Gone, stateWithoutSceneContainer = GONE)
.map { it == 1f }
.onStart { emit(false) },
keyguardTransitionInteractor
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModel.kt
index 02e48fc..10cfd6b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModel.kt
@@ -27,11 +27,13 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor
+import com.android.systemui.scene.shared.model.SceneFamilies
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.scene.shared.model.TransitionKeys.ToSplitShade
import com.android.systemui.shade.domain.interactor.ShadeInteractor
import com.android.systemui.shade.shared.model.ShadeMode
import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationsPlaceholderViewModel
+import com.android.systemui.util.kotlin.filterValuesNotNull
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -89,37 +91,36 @@
isCommunalAvailable: Boolean,
shadeMode: ShadeMode,
): Map<UserAction, UserActionResult> {
- val shadeSceneKey =
+ val notifShadeSceneKey =
UserActionResult(
- toScene =
- if (shadeMode is ShadeMode.Dual) Scenes.NotificationsShade else Scenes.Shade,
+ toScene = SceneFamilies.NotifShade,
transitionKey = ToSplitShade.takeIf { shadeMode is ShadeMode.Split },
)
- val quickSettingsIfSingleShade =
- if (shadeMode is ShadeMode.Single) UserActionResult(Scenes.QuickSettings)
- else shadeSceneKey
-
return mapOf(
Swipe.Left to UserActionResult(Scenes.Communal).takeIf { isCommunalAvailable },
Swipe.Up to if (isDeviceUnlocked) Scenes.Gone else Scenes.Bouncer,
// Swiping down from the top edge goes to QS (or shade if in split shade mode).
- swipeDownFromTop(pointerCount = 1) to quickSettingsIfSingleShade,
- swipeDownFromTop(pointerCount = 2) to
- // TODO(b/338577208): Remove 'Dual' once we add Dual Shade invocation zones.
- if (shadeMode is ShadeMode.Dual) {
- UserActionResult(Scenes.QuickSettingsShade)
+ swipeDownFromTop(pointerCount = 1) to
+ if (shadeMode is ShadeMode.Single) {
+ UserActionResult(Scenes.QuickSettings)
} else {
- quickSettingsIfSingleShade
+ notifShadeSceneKey
},
- // Swiping down, not from the edge, always navigates to the shade scene.
- swipeDown(pointerCount = 1) to shadeSceneKey,
- swipeDown(pointerCount = 2) to shadeSceneKey,
+ // TODO(b/338577208): Remove once we add Dual Shade invocation zones.
+ swipeDownFromTop(pointerCount = 2) to
+ UserActionResult(
+ toScene = SceneFamilies.QuickSettings,
+ transitionKey = ToSplitShade.takeIf { shadeMode is ShadeMode.Split }
+ ),
+
+ // Swiping down, not from the edge, always navigates to the notif shade scene.
+ swipeDown(pointerCount = 1) to notifShadeSceneKey,
+ swipeDown(pointerCount = 2) to notifShadeSceneKey,
)
- .filterValues { it != null }
- .mapValues { checkNotNull(it.value) }
+ .filterValuesNotNull()
}
private fun swipeDownFromTop(pointerCount: Int): Swipe {
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/data/repository/MediaFilterRepository.kt b/packages/SystemUI/src/com/android/systemui/media/controls/data/repository/MediaFilterRepository.kt
index 0c70f10..220d326 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/data/repository/MediaFilterRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/data/repository/MediaFilterRepository.kt
@@ -218,9 +218,9 @@
mediaFromRecPackageName = null
_currentMedia.value = sortedMap.values.toList()
}
- } else if (sortedMap.size > sortedMedia.size) {
+ } else if (sortedMap.size > sortedMedia.size && it.active) {
_currentMedia.value = sortedMap.values.toList()
- } else if (sortedMap.size == sortedMedia.size) {
+ } else {
// When loading an update for an existing media control.
val currentList =
mutableListOf<MediaCommonModel>().apply { addAll(_currentMedia.value) }
@@ -296,6 +296,18 @@
mediaFromRecPackageName = packageName
}
+ fun hasActiveMedia(): Boolean {
+ return _selectedUserEntries.value.any { it.value.active }
+ }
+
+ fun hasAnyMedia(): Boolean {
+ return _selectedUserEntries.value.entries.isNotEmpty()
+ }
+
+ fun isRecommendationActive(): Boolean {
+ return _smartspaceMediaData.value.isActive
+ }
+
private fun canBeRemoved(data: MediaData): Boolean {
return data.isPlaying?.let { !it } ?: data.isClearable && !data.active
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDeviceManager.kt b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDeviceManager.kt
index aa93df7..8b2f619 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDeviceManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDeviceManager.kt
@@ -358,7 +358,12 @@
// LocalMediaManager. Override with routing session name if available to
// show dynamic group name.
connectedDevice?.copy(name = it.name ?: connectedDevice.name)
- }
+ } ?: MediaDeviceData(
+ enabled = false,
+ icon = context.getDrawable(R.drawable.ic_media_home_devices),
+ name = context.getString(R.string.media_seamless_other_device),
+ showBroadcastButton = false
+ )
} else {
// Prefer SASS if available when playback is local.
activeDevice = getSassDevice() ?: connectedDevice
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/interactor/MediaCarouselInteractor.kt b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/interactor/MediaCarouselInteractor.kt
index b4bd4fd..0630cbd 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/interactor/MediaCarouselInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/interactor/MediaCarouselInteractor.kt
@@ -25,7 +25,6 @@
import com.android.systemui.CoreStartable
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
-import com.android.systemui.media.controls.data.repository.MediaDataRepository
import com.android.systemui.media.controls.data.repository.MediaFilterRepository
import com.android.systemui.media.controls.domain.pipeline.MediaDataCombineLatest
import com.android.systemui.media.controls.domain.pipeline.MediaDataFilterImpl
@@ -45,7 +44,6 @@
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
-import kotlinx.coroutines.flow.mapLatest
import kotlinx.coroutines.flow.stateIn
/** Encapsulates business logic for media pipeline. */
@@ -55,7 +53,6 @@
@Inject
constructor(
@Application applicationScope: CoroutineScope,
- private val mediaDataRepository: MediaDataRepository,
private val mediaDataProcessor: MediaDataProcessor,
private val mediaTimeoutListener: MediaTimeoutListener,
private val mediaResumeListener: MediaResumeListener,
@@ -103,26 +100,6 @@
initialValue = false,
)
- /** Are there any media notifications active, excluding the recommendations? */
- val hasActiveMedia: StateFlow<Boolean> =
- mediaFilterRepository.selectedUserEntries
- .mapLatest { entries -> entries.any { it.value.active } }
- .stateIn(
- scope = applicationScope,
- started = SharingStarted.WhileSubscribed(),
- initialValue = false,
- )
-
- /** Are there any media notifications, excluding the recommendations? */
- val hasAnyMedia: StateFlow<Boolean> =
- mediaFilterRepository.selectedUserEntries
- .mapLatest { entries -> entries.isNotEmpty() }
- .stateIn(
- scope = applicationScope,
- started = SharingStarted.WhileSubscribed(),
- initialValue = false,
- )
-
/** The current list for user media instances */
val currentMedia: StateFlow<List<MediaCommonModel>> = mediaFilterRepository.currentMedia
@@ -235,11 +212,11 @@
override fun hasAnyMediaOrRecommendation() = hasAnyMediaOrRecommendation.value
- override fun hasActiveMedia() = hasActiveMedia.value
+ override fun hasActiveMedia() = mediaFilterRepository.hasActiveMedia()
- override fun hasAnyMedia() = hasAnyMedia.value
+ override fun hasAnyMedia() = mediaFilterRepository.hasAnyMedia()
- override fun isRecommendationActive() = mediaDataRepository.smartspaceMediaData.value.isActive
+ override fun isRecommendationActive() = mediaFilterRepository.isRecommendationActive()
fun reorderMedia() {
mediaFilterRepository.setOrderedMedia()
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselController.kt
index 8f15561..987b370 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselController.kt
@@ -216,7 +216,7 @@
private var carouselLocale: Locale? = null
private val animationScaleObserver: ContentObserver =
- object : ContentObserver(null) {
+ object : ContentObserver(executor, 0) {
override fun onChange(selfChange: Boolean) {
if (!mediaFlags.isSceneContainerEnabled()) {
MediaPlayerData.players().forEach { it.updateAnimatorDurationScale() }
@@ -396,10 +396,12 @@
}
// Notifies all active players about animation scale changes.
- globalSettings.registerContentObserverSync(
- Settings.Global.getUriFor(Settings.Global.ANIMATOR_DURATION_SCALE),
- animationScaleObserver
- )
+ bgExecutor.execute {
+ globalSettings.registerContentObserverSync(
+ Settings.Global.getUriFor(Settings.Global.ANIMATOR_DURATION_SCALE),
+ animationScaleObserver
+ )
+ }
}
private fun setUpListeners() {
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaHierarchyManager.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaHierarchyManager.kt
index 601d563..88a28bf 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaHierarchyManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaHierarchyManager.kt
@@ -36,6 +36,7 @@
import com.android.app.animation.Interpolators
import com.android.app.tracing.traceSection
import com.android.keyguard.KeyguardViewController
+import com.android.systemui.Flags.mediaControlsLockscreenShadeBugFix
import com.android.systemui.communal.ui.viewmodel.CommunalTransitionViewModel
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
@@ -483,8 +484,7 @@
object : StatusBarStateController.StateListener {
override fun onStatePreChange(oldState: Int, newState: Int) {
// We're updating the location before the state change happens, since we want
- // the
- // location of the previous state to still be up to date when the animation
+ // the location of the previous state to still be up to date when the animation
// starts
if (
newState == StatusBarState.SHADE_LOCKED &&
@@ -588,6 +588,17 @@
}
}
+ if (mediaControlsLockscreenShadeBugFix()) {
+ coroutineScope.launch {
+ shadeInteractor.shadeExpansion.collect { expansion ->
+ if (expansion >= 1f || expansion <= 0f) {
+ // Shade has fully expanded or collapsed: force transition amount update
+ setTransitionToFullShadeAmount(expansion)
+ }
+ }
+ }
+ }
+
val settingsObserver: ContentObserver =
object : ContentObserver(handler) {
override fun onChange(selfChange: Boolean, uri: Uri?) {
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaCarouselViewModel.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaCarouselViewModel.kt
index 4e90936..315a9fb 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaCarouselViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaCarouselViewModel.kt
@@ -201,6 +201,7 @@
) {
if (immediatelyRemove || isReorderingAllowed()) {
interactor.dismissSmartspaceRecommendation(commonModel.recsLoadingModel.key, 0L)
+ mediaRecs = null
if (!immediatelyRemove) {
// Although it wasn't requested, we were able to process the removal
// immediately since reordering is allowed. So, notify hosts to update
diff --git a/packages/SystemUI/src/com/android/systemui/media/muteawait/MediaMuteAwaitConnectionManager.kt b/packages/SystemUI/src/com/android/systemui/media/muteawait/MediaMuteAwaitConnectionManager.kt
index f47954a..3a292e7 100644
--- a/packages/SystemUI/src/com/android/systemui/media/muteawait/MediaMuteAwaitConnectionManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/muteawait/MediaMuteAwaitConnectionManager.kt
@@ -94,7 +94,7 @@
}
private fun AudioDeviceAttributes.getIcon(): Drawable {
- return deviceIconUtil.getIconFromAudioDeviceType(this.type, context)
+ return deviceIconUtil.getIconFromAudioDeviceType(this.type)
}
private fun IntArray.hasMedia() = USAGE_MEDIA in this
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/RecentTaskListProvider.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/RecentTaskListProvider.kt
index 03adf1b..01b1be9 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/RecentTaskListProvider.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/RecentTaskListProvider.kt
@@ -58,7 +58,7 @@
// opening the app selector in split screen mode, the foreground task will be the second
// task in index 0.
val foregroundGroup =
- if (groupedTasks.first().splitBounds != null) groupedTasks.first()
+ if (groupedTasks.firstOrNull()?.splitBounds != null) groupedTasks.first()
else groupedTasks.elementAtOrNull(1)
val foregroundTaskId1 = foregroundGroup?.taskInfo1?.taskId
val foregroundTaskId2 = foregroundGroup?.taskInfo2?.taskId
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java
index e861ddf..f004c3a 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java
@@ -23,6 +23,7 @@
import static android.media.projection.MediaProjectionManager.OVERRIDE_DISABLE_MEDIA_PROJECTION_SINGLE_APP_OPTION;
import static android.media.projection.ReviewGrantedConsentResult.RECORD_CANCEL;
import static android.media.projection.ReviewGrantedConsentResult.RECORD_CONTENT_DISPLAY;
+import static android.os.UserHandle.USER_SYSTEM;
import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
import static com.android.systemui.mediaprojection.permission.ScreenShareOptionKt.ENTIRE_SCREEN;
@@ -31,7 +32,6 @@
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.app.Activity;
-import android.app.ActivityManager;
import android.app.ActivityOptions.LaunchCookie;
import android.app.AlertDialog;
import android.app.StatusBarManager;
@@ -366,11 +366,11 @@
intent.putExtra(EXTRA_USER_REVIEW_GRANTED_CONSENT, mReviewGrantedConsentRequired);
intent.setFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
- // Start activity from the current foreground user to avoid creating a separate
- // SystemUI process without access to recent tasks because it won't have
- // WM Shell running inside.
+ // Start activity as system user and manually show app selector to all users to
+ // avoid creating a separate SystemUI process without access to recent tasks
+ // because it won't have WM Shell running inside.
mUserSelectingTask = true;
- startActivityAsUser(intent, UserHandle.of(ActivityManager.getCurrentUser()));
+ startActivityAsUser(intent, UserHandle.of(USER_SYSTEM));
// close shade if it's open
mStatusBarManager.collapsePanels();
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index f3cc35ba..abc2b7f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -217,10 +217,13 @@
private void setBrightnessViewMargin() {
if (mBrightnessView != null) {
MarginLayoutParams lp = (MarginLayoutParams) mBrightnessView.getLayoutParams();
+ // For Brightness Slider to extend its boundary to draw focus background
+ int offset = getResources()
+ .getDimensionPixelSize(R.dimen.rounded_slider_boundary_offset);
lp.topMargin = mContext.getResources()
- .getDimensionPixelSize(R.dimen.qs_brightness_margin_top);
+ .getDimensionPixelSize(R.dimen.qs_brightness_margin_top) - offset;
lp.bottomMargin = mContext.getResources()
- .getDimensionPixelSize(R.dimen.qs_brightness_margin_bottom);
+ .getDimensionPixelSize(R.dimen.qs_brightness_margin_bottom) - offset;
mBrightnessView.setLayoutParams(lp);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java
index ea89be6..b705a03 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java
@@ -21,7 +21,6 @@
import android.content.Context;
import android.os.Handler;
-import com.android.systemui.bluetooth.qsdialog.BluetoothTileDialogModule;
import com.android.systemui.dagger.NightDisplayListenerModule;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Background;
@@ -61,7 +60,6 @@
*/
@Module(subcomponents = {QSFragmentComponent.class, QSSceneComponent.class},
includes = {
- BluetoothTileDialogModule.class,
MediaModule.class,
PanelsModule.class,
QSExternalModule.class,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PartitionedGridLayout.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PartitionedGridLayout.kt
index e1b21ef..9233e76 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PartitionedGridLayout.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PartitionedGridLayout.kt
@@ -16,7 +16,6 @@
package com.android.systemui.qs.panels.ui.compose
-import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
@@ -40,6 +39,13 @@
import androidx.compose.runtime.getValue
import androidx.compose.runtime.rememberUpdatedState
import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.drawWithContent
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.Path
+import androidx.compose.ui.graphics.PathEffect
+import androidx.compose.ui.graphics.Shape
+import androidx.compose.ui.graphics.addOutline
+import androidx.compose.ui.graphics.drawscope.Stroke
import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.Dp
@@ -268,10 +274,9 @@
private fun CurrentTilesContainer(content: @Composable () -> Unit) {
Box(
Modifier.fillMaxWidth()
- .border(
- width = 1.dp,
- color = MaterialTheme.colorScheme.onBackground,
- shape = RoundedCornerShape(dimensionResource(R.dimen.qs_corner_radius))
+ .dashedBorder(
+ color = MaterialTheme.colorScheme.onBackground.copy(alpha = .5f),
+ shape = Dimensions.ContainerShape,
)
.padding(dimensionResource(R.dimen.qs_tile_margin_vertical))
) {
@@ -286,7 +291,7 @@
.background(
color = MaterialTheme.colorScheme.background,
alpha = { 1f },
- shape = RoundedCornerShape(dimensionResource(R.dimen.qs_corner_radius))
+ shape = Dimensions.ContainerShape,
)
.padding(dimensionResource(R.dimen.qs_tile_margin_vertical))
) {
@@ -305,4 +310,27 @@
item(span = { GridItemSpan(maxCurrentLineSpan) }) { Spacer(Modifier) }
}
}
+
+ private fun Modifier.dashedBorder(
+ color: Color,
+ shape: Shape,
+ ): Modifier {
+ return this.drawWithContent {
+ val outline = shape.createOutline(size, layoutDirection, this)
+ val path = Path()
+ path.addOutline(outline)
+ val stroke =
+ Stroke(
+ width = 1.dp.toPx(),
+ pathEffect = PathEffect.dashPathEffect(floatArrayOf(10f, 10f))
+ )
+ this.drawContent()
+ drawPath(path = path, style = stroke, color = color)
+ }
+ }
+
+ private object Dimensions {
+ // Corner radius is half the height of a tile + padding
+ val ContainerShape = RoundedCornerShape(48.dp)
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/Tile.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/Tile.kt
index e4fbb4b..bbb98d3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/Tile.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/Tile.kt
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+@file:OptIn(ExperimentalFoundationApi::class)
+
package com.android.systemui.qs.panels.ui.compose
import android.graphics.drawable.Animatable
@@ -27,17 +29,17 @@
import androidx.compose.animation.graphics.vector.AnimatedImageVector
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.Image
-import androidx.compose.foundation.background
import androidx.compose.foundation.basicMarquee
-import androidx.compose.foundation.clickable
import androidx.compose.foundation.combinedClickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Arrangement.spacedBy
import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.BoxScope
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxHeight
-import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
@@ -46,11 +48,6 @@
import androidx.compose.foundation.lazy.grid.LazyGridScope
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.foundation.shape.CircleShape
-import androidx.compose.foundation.shape.RoundedCornerShape
-import androidx.compose.material.icons.Icons
-import androidx.compose.material.icons.filled.Add
-import androidx.compose.material.icons.filled.Remove
-import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
@@ -68,7 +65,6 @@
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.res.stringResource
-import androidx.compose.ui.semantics.contentDescription
import androidx.compose.ui.semantics.onClick
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.semantics.stateDescription
@@ -78,9 +74,11 @@
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.compose.animation.Expandable
+import com.android.systemui.animation.Expandable
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.common.ui.compose.Icon
import com.android.systemui.common.ui.compose.load
+import com.android.systemui.plugins.qs.QSTile
import com.android.systemui.qs.panels.ui.viewmodel.AvailableEditActions
import com.android.systemui.qs.panels.ui.viewmodel.EditTileViewModel
import com.android.systemui.qs.panels.ui.viewmodel.TileUiState
@@ -90,13 +88,14 @@
import com.android.systemui.qs.pipeline.shared.TileSpec
import com.android.systemui.qs.tileimpl.QSTileImpl
import com.android.systemui.res.R
+import java.util.function.Supplier
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.mapLatest
object TileType
-@OptIn(ExperimentalCoroutinesApi::class, ExperimentalFoundationApi::class)
+@OptIn(ExperimentalCoroutinesApi::class)
@Composable
fun Tile(
tile: TileViewModel,
@@ -110,46 +109,143 @@
.collectAsStateWithLifecycle(tile.currentState.toUiState())
val colors = TileDefaults.getColorForState(state.state)
- val context = LocalContext.current
-
- Expandable(
- color = colors.background,
- shape = RoundedCornerShape(dimensionResource(R.dimen.qs_corner_radius)),
+ TileContainer(
+ colors = colors,
+ showLabels = showLabels,
+ label = state.label.toString(),
+ iconOnly = iconOnly,
+ onClick = tile::onClick,
+ onLongClick = tile::onLongClick,
+ modifier = modifier,
) {
- Row(
- modifier =
- modifier
- .combinedClickable(
- onClick = { tile.onClick(it) },
- onLongClick = { tile.onLongClick(it) }
- )
- .tileModifier(colors),
- verticalAlignment = Alignment.CenterVertically,
- horizontalArrangement = tileHorizontalArrangement(iconOnly),
- ) {
- val icon =
- remember(state.icon) {
- state.icon.get().let {
- if (it is QSTileImpl.ResourceIcon) {
- Icon.Resource(it.resId, null)
- } else {
- Icon.Loaded(it.getDrawable(context), null)
- }
- }
- }
- TileContent(
+ val icon = getTileIcon(icon = state.icon)
+ if (iconOnly) {
+ TileIcon(icon = icon, color = colors.icon, modifier = Modifier.align(Alignment.Center))
+ } else {
+ LargeTileContent(
label = state.label.toString(),
secondaryLabel = state.secondaryLabel.toString(),
icon = icon,
colors = colors,
- iconOnly = iconOnly,
- showLabels = showLabels,
+ onClick = tile::onSecondaryClick,
+ onLongClick = tile::onLongClick,
)
}
}
}
@Composable
+private fun TileContainer(
+ colors: TileColors,
+ showLabels: Boolean,
+ label: String,
+ iconOnly: Boolean,
+ clickEnabled: Boolean = true,
+ onClick: (Expandable) -> Unit = {},
+ onLongClick: (Expandable) -> Unit = {},
+ modifier: Modifier = Modifier,
+ content: @Composable BoxScope.() -> Unit,
+) {
+ Column(
+ horizontalAlignment = Alignment.CenterHorizontally,
+ verticalArrangement =
+ spacedBy(dimensionResource(id = R.dimen.qs_label_container_margin), Alignment.Top),
+ modifier = modifier,
+ ) {
+ val backgroundColor =
+ if (iconOnly) {
+ colors.iconBackground
+ } else {
+ colors.background
+ }
+ Expandable(
+ color = backgroundColor,
+ shape = TileDefaults.TileShape,
+ modifier =
+ Modifier.height(dimensionResource(id = R.dimen.qs_tile_height))
+ .clip(TileDefaults.TileShape)
+ ) {
+ Box(
+ modifier =
+ Modifier.fillMaxSize()
+ .combinedClickable(
+ enabled = clickEnabled,
+ onClick = { onClick(it) },
+ onLongClick = { onLongClick(it) }
+ )
+ .tilePadding(),
+ ) {
+ content()
+ }
+ }
+
+ if (showLabels && iconOnly) {
+ Text(
+ label,
+ maxLines = 2,
+ color = colors.label,
+ overflow = TextOverflow.Ellipsis,
+ textAlign = TextAlign.Center,
+ )
+ }
+ }
+}
+
+@Composable
+private fun LargeTileContent(
+ label: String,
+ secondaryLabel: String?,
+ icon: Icon,
+ colors: TileColors,
+ clickEnabled: Boolean = true,
+ onClick: (Expandable) -> Unit = {},
+ onLongClick: (Expandable) -> Unit = {},
+) {
+ Row(
+ verticalAlignment = Alignment.CenterVertically,
+ horizontalArrangement = tileHorizontalArrangement()
+ ) {
+ Expandable(
+ color = colors.iconBackground,
+ shape = TileDefaults.TileShape,
+ modifier = Modifier.fillMaxHeight().aspectRatio(1f)
+ ) {
+ Box(
+ modifier =
+ Modifier.fillMaxSize()
+ .clip(TileDefaults.TileShape)
+ .combinedClickable(
+ enabled = clickEnabled,
+ onClick = { onClick(it) },
+ onLongClick = { onLongClick(it) }
+ )
+ ) {
+ TileIcon(
+ icon = icon,
+ color = colors.icon,
+ modifier = Modifier.align(Alignment.Center)
+ )
+ }
+ }
+
+ Column(verticalArrangement = Arrangement.Center, modifier = Modifier.fillMaxHeight()) {
+ Text(
+ label,
+ color = colors.label,
+ modifier = Modifier.basicMarquee(),
+ )
+ if (!TextUtils.isEmpty(secondaryLabel)) {
+ Text(
+ secondaryLabel ?: "",
+ color = colors.secondaryLabel,
+ modifier = Modifier.basicMarquee(),
+ )
+ }
+ }
+ }
+}
+
+@Composable
fun TileLazyGrid(
modifier: Modifier = Modifier,
columns: GridCells,
@@ -247,41 +343,19 @@
""
}
- Box(
+ val iconOnly = isIconOnly(viewModel.tileSpec)
+ val tileHeight = tileHeight(iconOnly && showLabels)
+ EditTile(
+ tileViewModel = viewModel,
+ iconOnly = iconOnly,
+ showLabels = showLabels,
+ clickEnabled = canClick,
+ onClick = { onClick.invoke(viewModel.tileSpec) },
modifier =
- Modifier.clickable(enabled = canClick) { onClick.invoke(viewModel.tileSpec) }
- .animateItem()
- .semantics {
- onClick(onClickActionName) { false }
- this.stateDescription = stateDescription
- }
- ) {
- val iconOnly = isIconOnly(viewModel.tileSpec)
- val tileHeight = tileHeight(iconOnly && showLabels)
- EditTile(
- tileViewModel = viewModel,
- iconOnly = iconOnly,
- showLabels = showLabels,
- modifier = Modifier.height(tileHeight)
- )
- if (canClick) {
- Badge(clickAction, Modifier.align(Alignment.TopEnd))
- }
- }
- }
-}
-
-@Composable
-fun Badge(action: ClickAction, modifier: Modifier = Modifier) {
- Box(modifier = modifier.size(16.dp).background(Color.Cyan, shape = CircleShape)) {
- Icon(
- imageVector =
- when (action) {
- ClickAction.ADD -> Icons.Filled.Add
- ClickAction.REMOVE -> Icons.Filled.Remove
- },
- "",
- tint = Color.Black,
+ Modifier.height(tileHeight).animateItem().semantics {
+ onClick(onClickActionName) { false }
+ this.stateDescription = stateDescription
+ }
)
}
}
@@ -291,25 +365,40 @@
tileViewModel: EditTileViewModel,
iconOnly: Boolean,
showLabels: Boolean,
+ clickEnabled: Boolean,
+ onClick: () -> Unit,
modifier: Modifier = Modifier,
) {
val label = tileViewModel.label.load() ?: tileViewModel.tileSpec.spec
val colors = TileDefaults.inactiveTileColors()
- Row(
- modifier = modifier.tileModifier(colors).semantics { this.contentDescription = label },
- verticalAlignment = Alignment.CenterVertically,
- horizontalArrangement = tileHorizontalArrangement(iconOnly)
+ TileContainer(
+ colors = colors,
+ showLabels = showLabels,
+ label = label,
+ iconOnly = iconOnly,
+ clickEnabled = clickEnabled,
+ onClick = { onClick() },
+ onLongClick = { onClick() },
+ modifier = modifier,
) {
- TileContent(
- label = label,
- secondaryLabel = tileViewModel.appName?.load(),
- colors = colors,
- icon = tileViewModel.icon,
- iconOnly = iconOnly,
- showLabels = showLabels,
- animateIconToEnd = true,
- )
+ if (iconOnly) {
+ TileIcon(
+ icon = tileViewModel.icon,
+ color = colors.icon,
+ modifier = Modifier.align(Alignment.Center)
+ )
+ } else {
+ LargeTileContent(
+ label = label,
+ secondaryLabel = tileViewModel.appName?.load(),
+ icon = tileViewModel.icon,
+ colors = colors,
+ clickEnabled = clickEnabled,
+ onClick = { onClick() },
+ onLongClick = { onClick() },
+ )
+ }
}
}
@@ -318,14 +407,27 @@
REMOVE,
}
+@Composable
+private fun getTileIcon(icon: Supplier<QSTile.Icon>): Icon {
+ val context = LocalContext.current
+ return icon.get().let {
+ if (it is QSTileImpl.ResourceIcon) {
+ Icon.Resource(it.resId, null)
+ } else {
+ Icon.Loaded(it.getDrawable(context), null)
+ }
+ }
+}
+
@OptIn(ExperimentalAnimationGraphicsApi::class)
@Composable
private fun TileIcon(
icon: Icon,
color: Color,
animateToEnd: Boolean = false,
+ modifier: Modifier = Modifier,
) {
- val modifier = Modifier.size(dimensionResource(id = R.dimen.qs_icon_size))
+ val iconModifier = modifier.size(dimensionResource(id = R.dimen.qs_icon_size))
val context = LocalContext.current
val loadedDrawable =
remember(icon, context) {
@@ -338,7 +440,7 @@
Icon(
icon = icon,
tint = color,
- modifier = modifier,
+ modifier = iconModifier,
)
} else if (icon is Icon.Resource) {
val image = AnimatedImageVector.animatedVectorResource(id = icon.res)
@@ -357,80 +459,25 @@
painter = painter,
contentDescription = null,
colorFilter = ColorFilter.tint(color = color),
- modifier = modifier
+ modifier = iconModifier
)
}
}
@Composable
-private fun Modifier.tileModifier(colors: TileColors): Modifier {
- return fillMaxWidth()
- .clip(RoundedCornerShape(dimensionResource(R.dimen.qs_corner_radius)))
- .background(colors.background)
- .padding(horizontal = dimensionResource(id = R.dimen.qs_label_container_margin))
+private fun Modifier.tilePadding(): Modifier {
+ return padding(dimensionResource(id = R.dimen.qs_label_container_margin))
}
@Composable
-private fun tileHorizontalArrangement(iconOnly: Boolean): Arrangement.Horizontal {
- val horizontalAlignment =
- if (iconOnly) {
- Alignment.CenterHorizontally
- } else {
- Alignment.Start
- }
+private fun tileHorizontalArrangement(): Arrangement.Horizontal {
return spacedBy(
space = dimensionResource(id = R.dimen.qs_label_container_margin),
- alignment = horizontalAlignment
+ alignment = Alignment.Start
)
}
@Composable
-private fun TileContent(
- label: String,
- secondaryLabel: String?,
- icon: Icon,
- colors: TileColors,
- iconOnly: Boolean,
- showLabels: Boolean = false,
- animateIconToEnd: Boolean = false,
-) {
- Column(
- horizontalAlignment = Alignment.CenterHorizontally,
- verticalArrangement = Arrangement.Center,
- modifier = Modifier.fillMaxHeight()
- ) {
- TileIcon(icon, colors.icon, animateIconToEnd)
-
- if (iconOnly && showLabels) {
- Text(
- label,
- maxLines = 2,
- color = colors.label,
- overflow = TextOverflow.Ellipsis,
- textAlign = TextAlign.Center,
- )
- }
- }
-
- if (!iconOnly) {
- Column(verticalArrangement = Arrangement.Center, modifier = Modifier.fillMaxHeight()) {
- Text(
- label,
- color = colors.label,
- modifier = Modifier.basicMarquee(),
- )
- if (!TextUtils.isEmpty(secondaryLabel)) {
- Text(
- secondaryLabel ?: "",
- color = colors.secondaryLabel,
- modifier = Modifier.basicMarquee(),
- )
- }
- }
- }
-}
-
-@Composable
fun tileHeight(iconWithLabel: Boolean = false): Dp {
return if (iconWithLabel) {
TileDefaults.IconTileWithLabelHeight
@@ -441,20 +488,23 @@
private data class TileColors(
val background: Color,
+ val iconBackground: Color,
val label: Color,
val secondaryLabel: Color,
val icon: Color,
)
private object TileDefaults {
- val IconTileWithLabelHeight = 100.dp
+ val TileShape = CircleShape
+ val IconTileWithLabelHeight = 140.dp
@Composable
fun activeTileColors(): TileColors =
TileColors(
- background = MaterialTheme.colorScheme.primary,
- label = MaterialTheme.colorScheme.onPrimary,
- secondaryLabel = MaterialTheme.colorScheme.onPrimary,
+ background = MaterialTheme.colorScheme.surfaceVariant,
+ iconBackground = MaterialTheme.colorScheme.primary,
+ label = MaterialTheme.colorScheme.onSurfaceVariant,
+ secondaryLabel = MaterialTheme.colorScheme.onSurfaceVariant,
icon = MaterialTheme.colorScheme.onPrimary,
)
@@ -462,6 +512,7 @@
fun inactiveTileColors(): TileColors =
TileColors(
background = MaterialTheme.colorScheme.surfaceVariant,
+ iconBackground = MaterialTheme.colorScheme.surfaceVariant,
label = MaterialTheme.colorScheme.onSurfaceVariant,
secondaryLabel = MaterialTheme.colorScheme.onSurfaceVariant,
icon = MaterialTheme.colorScheme.onSurfaceVariant,
@@ -471,6 +522,7 @@
fun unavailableTileColors(): TileColors =
TileColors(
background = MaterialTheme.colorScheme.surface,
+ iconBackground = MaterialTheme.colorScheme.surface,
label = MaterialTheme.colorScheme.onSurface,
secondaryLabel = MaterialTheme.colorScheme.onSurface,
icon = MaterialTheme.colorScheme.onSurface,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/TileViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/TileViewModel.kt
index a6cfa75..7505b90 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/TileViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/TileViewModel.kt
@@ -48,6 +48,10 @@
tile.longClick(expandable)
}
+ fun onSecondaryClick(expandable: Expandable?) {
+ tile.secondaryClick(expandable)
+ }
+
fun startListening(token: Any) = tile.setListening(token, true)
fun stopListening(token: Any) = tile.setListening(token, false)
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
index 1143c30..b1b67cf 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
@@ -19,6 +19,7 @@
import android.animation.ArgbEvaluator
import android.animation.PropertyValuesHolder
import android.animation.ValueAnimator
+import android.annotation.SuppressLint
import android.content.Context
import android.content.res.ColorStateList
import android.content.res.Configuration
@@ -37,27 +38,31 @@
import android.util.TypedValue
import android.view.Gravity
import android.view.LayoutInflater
+import android.view.MotionEvent
import android.view.View
+import android.view.ViewConfiguration
import android.view.ViewGroup
import android.view.accessibility.AccessibilityEvent
import android.view.accessibility.AccessibilityNodeInfo
+import android.view.animation.AccelerateDecelerateInterpolator
import android.widget.Button
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.Switch
import android.widget.TextView
import androidx.annotation.VisibleForTesting
+import androidx.core.animation.doOnCancel
+import androidx.core.animation.doOnEnd
+import androidx.core.animation.doOnStart
import androidx.core.graphics.drawable.updateBounds
import com.android.app.tracing.traceSection
import com.android.settingslib.Utils
import com.android.systemui.Flags
-import com.android.systemui.Flags.quickSettingsVisualHapticsLongpress
import com.android.systemui.FontSizeUtils
import com.android.systemui.animation.Expandable
import com.android.systemui.animation.LaunchableView
import com.android.systemui.animation.LaunchableViewDelegate
import com.android.systemui.haptics.qs.QSLongPressEffect
-import com.android.systemui.haptics.qs.QSLongPressEffectViewBinder
import com.android.systemui.plugins.qs.QSIconView
import com.android.systemui.plugins.qs.QSTile
import com.android.systemui.plugins.qs.QSTile.AdapterState
@@ -65,11 +70,13 @@
import com.android.systemui.qs.logging.QSLogger
import com.android.systemui.qs.tileimpl.QSIconViewImpl.QS_ANIM_LENGTH
import com.android.systemui.res.R
-import kotlinx.coroutines.DisposableHandle
import java.util.Objects
private const val TAG = "QSTileViewImpl"
-open class QSTileViewImpl @JvmOverloads constructor(
+
+open class QSTileViewImpl
+@JvmOverloads
+constructor(
context: Context,
private val collapsed: Boolean = false,
private val longPressEffect: QSLongPressEffect? = null,
@@ -83,12 +90,9 @@
private const val CHEVRON_NAME = "chevron"
private const val OVERLAY_NAME = "overlay"
const val UNAVAILABLE_ALPHA = 0.3f
- @VisibleForTesting
- internal const val TILE_STATE_RES_PREFIX = "tile_states_"
- @VisibleForTesting
- internal const val LONG_PRESS_EFFECT_WIDTH_SCALE = 1.1f
- @VisibleForTesting
- internal const val LONG_PRESS_EFFECT_HEIGHT_SCALE = 1.2f
+ @VisibleForTesting internal const val TILE_STATE_RES_PREFIX = "tile_states_"
+ @VisibleForTesting internal const val LONG_PRESS_EFFECT_WIDTH_SCALE = 1.1f
+ @VisibleForTesting internal const val LONG_PRESS_EFFECT_HEIGHT_SCALE = 1.2f
}
private val icon: QSIconViewImpl = QSIconViewImpl(context)
@@ -116,22 +120,25 @@
private val colorInactive = Utils.getColorAttrDefaultColor(context, R.attr.shadeInactive)
private val colorUnavailable = Utils.getColorAttrDefaultColor(context, R.attr.shadeDisabled)
- private val overlayColorActive = Utils.applyAlpha(
- /* alpha= */ 0.11f,
- Utils.getColorAttrDefaultColor(context, R.attr.onShadeActive))
- private val overlayColorInactive = Utils.applyAlpha(
- /* alpha= */ 0.08f,
- Utils.getColorAttrDefaultColor(context, R.attr.onShadeInactive))
+ private val overlayColorActive =
+ Utils.applyAlpha(
+ /* alpha= */ 0.11f,
+ Utils.getColorAttrDefaultColor(context, R.attr.onShadeActive)
+ )
+ private val overlayColorInactive =
+ Utils.applyAlpha(
+ /* alpha= */ 0.08f,
+ Utils.getColorAttrDefaultColor(context, R.attr.onShadeInactive)
+ )
private val colorLabelActive = Utils.getColorAttrDefaultColor(context, R.attr.onShadeActive)
private val colorLabelInactive = Utils.getColorAttrDefaultColor(context, R.attr.onShadeInactive)
- private val colorLabelUnavailable =
- Utils.getColorAttrDefaultColor(context, R.attr.outline)
+ private val colorLabelUnavailable = Utils.getColorAttrDefaultColor(context, R.attr.outline)
private val colorSecondaryLabelActive =
Utils.getColorAttrDefaultColor(context, R.attr.onShadeActiveVariant)
private val colorSecondaryLabelInactive =
- Utils.getColorAttrDefaultColor(context, R.attr.onShadeInactiveVariant)
+ Utils.getColorAttrDefaultColor(context, R.attr.onShadeInactiveVariant)
private val colorSecondaryLabelUnavailable =
Utils.getColorAttrDefaultColor(context, R.attr.outline)
@@ -143,9 +150,7 @@
private lateinit var chevronView: ImageView
private var mQsLogger: QSLogger? = null
- /**
- * Controls if tile background is set to a [RippleDrawable] see [setClickable]
- */
+ /** Controls if tile background is set to a [RippleDrawable] see [setClickable] */
protected var showRippleEffect = true
private lateinit var qsTileBackground: RippleDrawable
@@ -157,20 +162,21 @@
private var backgroundColor: Int = 0
private var backgroundOverlayColor: Int = 0
- private val singleAnimator: ValueAnimator = ValueAnimator().apply {
- setDuration(QS_ANIM_LENGTH)
- addUpdateListener { animation ->
- setAllColors(
- // These casts will throw an exception if some property is missing. We should
- // always have all properties.
- animation.getAnimatedValue(BACKGROUND_NAME) as Int,
- animation.getAnimatedValue(LABEL_NAME) as Int,
- animation.getAnimatedValue(SECONDARY_LABEL_NAME) as Int,
- animation.getAnimatedValue(CHEVRON_NAME) as Int,
- animation.getAnimatedValue(OVERLAY_NAME) as Int,
- )
+ private val singleAnimator: ValueAnimator =
+ ValueAnimator().apply {
+ setDuration(QS_ANIM_LENGTH)
+ addUpdateListener { animation ->
+ setAllColors(
+ // These casts will throw an exception if some property is missing. We should
+ // always have all properties.
+ animation.getAnimatedValue(BACKGROUND_NAME) as Int,
+ animation.getAnimatedValue(LABEL_NAME) as Int,
+ animation.getAnimatedValue(SECONDARY_LABEL_NAME) as Int,
+ animation.getAnimatedValue(CHEVRON_NAME) as Int,
+ animation.getAnimatedValue(OVERLAY_NAME) as Int,
+ )
+ }
}
- }
private var accessibilityClass: String? = null
private var stateDescriptionDeltas: CharSequence? = null
@@ -178,32 +184,37 @@
private var tileState = false
private var lastState = INVALID
private var lastIconTint = 0
- private val launchableViewDelegate = LaunchableViewDelegate(
- this,
- superSetVisibility = { super.setVisibility(it) },
- )
+ private val launchableViewDelegate =
+ LaunchableViewDelegate(
+ this,
+ superSetVisibility = { super.setVisibility(it) },
+ )
private var lastDisabledByPolicy = false
private val locInScreen = IntArray(2)
/** Visuo-haptic long-press effects */
+ private var longPressEffectAnimator: ValueAnimator? = null
var haveLongPressPropertiesBeenReset = true
private set
+
private var paddingForLaunch = Rect()
private var initialLongPressProperties: QSLongPressProperties? = null
private var finalLongPressProperties: QSLongPressProperties? = null
private val colorEvaluator = ArgbEvaluator.getInstance()
val isLongPressEffectInitialized: Boolean
get() = longPressEffect?.hasInitialized == true
- private var longPressEffectHandle: DisposableHandle? = null
- val isLongPressEffectBound: Boolean
- get() = longPressEffectHandle != null
+
+ val areLongPressEffectPropertiesSet: Boolean
+ get() = initialLongPressProperties != null && finalLongPressProperties != null
init {
val typedValue = TypedValue()
if (!getContext().theme.resolveAttribute(R.attr.isQsTheme, typedValue, true)) {
- throw IllegalStateException("QSViewImpl must be inflated with a theme that contains " +
- "Theme.SystemUI.QuickSettings")
+ throw IllegalStateException(
+ "QSViewImpl must be inflated with a theme that contains " +
+ "Theme.SystemUI.QuickSettings"
+ )
}
setId(generateViewId())
orientation = LinearLayout.HORIZONTAL
@@ -261,13 +272,9 @@
setPaddingRelative(startPadding, padding, padding, padding)
val labelMargin = resources.getDimensionPixelSize(R.dimen.qs_label_container_margin)
- (labelContainer.layoutParams as MarginLayoutParams).apply {
- marginStart = labelMargin
- }
+ (labelContainer.layoutParams as MarginLayoutParams).apply { marginStart = labelMargin }
- (sideView.layoutParams as MarginLayoutParams).apply {
- marginStart = labelMargin
- }
+ (sideView.layoutParams as MarginLayoutParams).apply { marginStart = labelMargin }
(chevronView.layoutParams as MarginLayoutParams).apply {
height = iconSize
width = iconSize
@@ -285,8 +292,9 @@
}
private fun createAndAddLabels() {
- labelContainer = LayoutInflater.from(context)
- .inflate(R.layout.qs_tile_label, this, false) as IgnorableChildLinearLayout
+ labelContainer =
+ LayoutInflater.from(context).inflate(R.layout.qs_tile_label, this, false)
+ as IgnorableChildLinearLayout
label = labelContainer.requireViewById(R.id.tile_label)
secondaryLabel = labelContainer.requireViewById(R.id.app_label)
if (collapsed) {
@@ -304,8 +312,9 @@
}
private fun createAndAddSideView() {
- sideView = LayoutInflater.from(context)
- .inflate(R.layout.qs_tile_side_icon, this, false) as ViewGroup
+ sideView =
+ LayoutInflater.from(context).inflate(R.layout.qs_tile_side_icon, this, false)
+ as ViewGroup
customDrawableView = sideView.requireViewById(R.id.customDrawable)
chevronView = sideView.requireViewById(R.id.chevron)
setChevronColor(getChevronColorForState(QSTile.State.DEFAULT_STATE))
@@ -313,11 +322,12 @@
}
private fun createTileBackground(): Drawable {
- qsTileBackground = if (Flags.qsTileFocusState()) {
- mContext.getDrawable(R.drawable.qs_tile_background_flagged) as RippleDrawable
- } else {
- mContext.getDrawable(R.drawable.qs_tile_background) as RippleDrawable
- }
+ qsTileBackground =
+ if (Flags.qsTileFocusState()) {
+ mContext.getDrawable(R.drawable.qs_tile_background_flagged) as RippleDrawable
+ } else {
+ mContext.getDrawable(R.drawable.qs_tile_background) as RippleDrawable
+ }
qsTileFocusBackground = mContext.getDrawable(R.drawable.qs_tile_focused_background)!!
backgroundDrawable =
qsTileBackground.findDrawableByLayerId(R.id.background) as LayerDrawable
@@ -332,21 +342,21 @@
override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
super.onLayout(changed, l, t, r, b)
updateHeight()
- maybeUpdateLongPressEffectDimensions()
+ maybeUpdateLongPressEffectWidth(measuredWidth.toFloat())
}
- private fun maybeUpdateLongPressEffectDimensions() {
+ private fun maybeUpdateLongPressEffectWidth(width: Float) {
if (!isLongClickable || longPressEffect == null) return
- val actualHeight = if (heightOverride != HeightOverrideable.NO_OVERRIDE) {
- heightOverride
- } else {
- measuredHeight
- }
- initialLongPressProperties?.height = actualHeight.toFloat()
- initialLongPressProperties?.width = measuredWidth.toFloat()
- finalLongPressProperties?.height = LONG_PRESS_EFFECT_HEIGHT_SCALE * actualHeight
- finalLongPressProperties?.width = LONG_PRESS_EFFECT_WIDTH_SCALE * measuredWidth
+ initialLongPressProperties?.width = width
+ finalLongPressProperties?.width = LONG_PRESS_EFFECT_WIDTH_SCALE * width
+ }
+
+ private fun maybeUpdateLongPressEffectHeight(height: Float) {
+ if (!isLongClickable || longPressEffect == null) return
+
+ initialLongPressProperties?.height = height
+ finalLongPressProperties?.height = LONG_PRESS_EFFECT_HEIGHT_SCALE * height
}
override fun onFocusChanged(gainFocus: Boolean, direction: Int, previouslyFocusedRect: Rect?) {
@@ -360,6 +370,7 @@
}
}
}
+
private fun updateHeight() {
// TODO(b/332900989): Find a more robust way of resetting the tile if not reset by the
// launch animation.
@@ -368,16 +379,18 @@
// we must do it here
resetLongPressEffectProperties()
}
- val actualHeight = if (heightOverride != HeightOverrideable.NO_OVERRIDE) {
- heightOverride
- } else {
- measuredHeight
- }
+ val actualHeight =
+ if (heightOverride != HeightOverrideable.NO_OVERRIDE) {
+ heightOverride
+ } else {
+ measuredHeight
+ }
// Limit how much we affect the height, so we don't have rounding artifacts when the tile
// is too short.
val constrainedSquishiness = constrainSquishiness(squishinessFraction)
bottom = top + (actualHeight * constrainedSquishiness).toInt()
scrollY = (actualHeight - height) / 2
+ maybeUpdateLongPressEffectHeight(actualHeight.toFloat())
}
override fun updateAccessibilityOrder(previousView: View?): View {
@@ -395,22 +408,77 @@
override fun init(tile: QSTile) {
val expandable = Expandable.fromView(this)
- init(
+ if (longPressEffect != null) {
+ isHapticFeedbackEnabled = false
+ longPressEffect.qsTile = tile
+ longPressEffect.expandable = expandable
+ initLongPressEffectCallback()
+ init(
+ { _: View -> longPressEffect.onTileClick() },
+ null, // Haptics and long-clicks will be handled by the [QSLongPressEffect]
+ )
+ } else {
+ init(
{ _: View? -> tile.click(expandable) },
{ _: View? ->
tile.longClick(expandable)
true
- }
- )
- if (quickSettingsVisualHapticsLongpress()) {
- isHapticFeedbackEnabled = false // Haptics will be handled by the [QSLongPressEffect]
+ },
+ )
}
}
- private fun init(
- click: OnClickListener?,
- longClick: OnLongClickListener?
- ) {
+ private fun initLongPressEffectCallback() {
+ longPressEffect?.callback =
+ object : QSLongPressEffect.Callback {
+
+ override fun onPrepareForLaunch() {
+ prepareForLaunch()
+ }
+
+ override fun onResetProperties() {
+ resetLongPressEffectProperties()
+ }
+
+ override fun onStartAnimator() {
+ if (longPressEffectAnimator?.isRunning != true) {
+ longPressEffectAnimator =
+ ValueAnimator.ofFloat(0f, 1f).apply {
+ this.duration = longPressEffect?.effectDuration?.toLong() ?: 0L
+ interpolator = AccelerateDecelerateInterpolator()
+
+ doOnStart { longPressEffect?.handleAnimationStart() }
+ addUpdateListener {
+ val value = animatedValue as Float
+ if (value == 0f) {
+ bringToFront()
+ } else {
+ updateLongPressEffectProperties(value)
+ }
+ }
+ doOnEnd { longPressEffect?.handleAnimationComplete() }
+ doOnCancel { longPressEffect?.handleAnimationCancel() }
+ start()
+ }
+ }
+ }
+
+ override fun onReverseAnimator() {
+ longPressEffectAnimator?.let {
+ val pausedProgress = it.animatedFraction
+ longPressEffect?.playReverseHaptics(pausedProgress)
+ it.reverse()
+ }
+ }
+
+ override fun onCancelAnimator() {
+ resetLongPressEffectProperties()
+ longPressEffectAnimator?.cancel()
+ }
+ }
+ }
+
+ private fun init(click: OnClickListener?, longClick: OnLongClickListener?) {
setOnClickListener(click)
onLongClickListener = longClick
}
@@ -438,16 +506,18 @@
override fun setClickable(clickable: Boolean) {
super.setClickable(clickable)
- if (!Flags.qsTileFocusState()){
- background = if (clickable && showRippleEffect) {
- qsTileBackground.also {
- // In case that the colorBackgroundDrawable was used as the background, make sure
- // it has the correct callback instead of null
- backgroundDrawable.callback = it
+ if (!Flags.qsTileFocusState()) {
+ background =
+ if (clickable && showRippleEffect) {
+ qsTileBackground.also {
+ // In case that the colorBackgroundDrawable was used as the background, make
+ // sure
+ // it has the correct callback instead of null
+ backgroundDrawable.callback = it
+ }
+ } else {
+ backgroundDrawable
}
- } else {
- backgroundDrawable
- }
}
}
@@ -482,8 +552,10 @@
if (!TextUtils.isEmpty(accessibilityClass)) {
event.className = accessibilityClass
}
- if (event.contentChangeTypes == AccessibilityEvent.CONTENT_CHANGE_TYPE_STATE_DESCRIPTION &&
- stateDescriptionDeltas != null) {
+ if (
+ event.contentChangeTypes == AccessibilityEvent.CONTENT_CHANGE_TYPE_STATE_DESCRIPTION &&
+ stateDescriptionDeltas != null
+ ) {
event.text.add(stateDescriptionDeltas)
stateDescriptionDeltas = null
}
@@ -493,36 +565,39 @@
super.onInitializeAccessibilityNodeInfo(info)
// Clear selected state so it is not announce by talkback.
info.isSelected = false
- info.text = if (TextUtils.isEmpty(secondaryLabel.text)) {
- "${label.text}"
- } else {
- "${label.text}, ${secondaryLabel.text}"
- }
+ info.text =
+ if (TextUtils.isEmpty(secondaryLabel.text)) {
+ "${label.text}"
+ } else {
+ "${label.text}, ${secondaryLabel.text}"
+ }
if (lastDisabledByPolicy) {
info.addAction(
- AccessibilityNodeInfo.AccessibilityAction(
- AccessibilityNodeInfo.AccessibilityAction.ACTION_CLICK.id,
- resources.getString(
- R.string.accessibility_tile_disabled_by_policy_action_description
- )
+ AccessibilityNodeInfo.AccessibilityAction(
+ AccessibilityNodeInfo.AccessibilityAction.ACTION_CLICK.id,
+ resources.getString(
+ R.string.accessibility_tile_disabled_by_policy_action_description
)
+ )
)
}
if (!TextUtils.isEmpty(accessibilityClass)) {
- info.className = if (lastDisabledByPolicy) {
- Button::class.java.name
- } else {
- accessibilityClass
- }
+ info.className =
+ if (lastDisabledByPolicy) {
+ Button::class.java.name
+ } else {
+ accessibilityClass
+ }
if (Switch::class.java.name == accessibilityClass) {
info.isChecked = tileState
info.isCheckable = true
if (isLongClickable) {
info.addAction(
- AccessibilityNodeInfo.AccessibilityAction(
- AccessibilityNodeInfo.AccessibilityAction.ACTION_LONG_CLICK.id,
- resources.getString(
- R.string.accessibility_long_click_tile)))
+ AccessibilityNodeInfo.AccessibilityAction(
+ AccessibilityNodeInfo.AccessibilityAction.ACTION_LONG_CLICK.id,
+ resources.getString(R.string.accessibility_long_click_tile)
+ )
+ )
}
}
}
@@ -541,6 +616,28 @@
return sb.toString()
}
+ @SuppressLint("ClickableViewAccessibility")
+ override fun onTouchEvent(event: MotionEvent?): Boolean {
+ // let the View run the onTouch logic for click and long-click detection
+ val result = super.onTouchEvent(event)
+ if (longPressEffect != null) {
+ when (event?.actionMasked) {
+ MotionEvent.ACTION_DOWN -> {
+ longPressEffect.handleActionDown()
+ if (isLongClickable) {
+ postDelayed(
+ { longPressEffect.handleTimeoutComplete() },
+ ViewConfiguration.getTapTimeout().toLong(),
+ )
+ }
+ }
+ MotionEvent.ACTION_UP -> longPressEffect.handleActionUp()
+ MotionEvent.ACTION_CANCEL -> longPressEffect.handleActionCancel()
+ }
+ }
+ return result
+ }
+
// HANDLE STATE CHANGES RELATED METHODS
protected open fun handleStateChanged(state: QSTile.State) {
@@ -565,8 +662,11 @@
if (!TextUtils.isEmpty(state.stateDescription)) {
stateDescription.append(", ")
stateDescription.append(state.stateDescription)
- if (lastState != INVALID && state.state == lastState &&
- state.stateDescription != lastStateDescription) {
+ if (
+ lastState != INVALID &&
+ state.state == lastState &&
+ state.stateDescription != lastStateDescription
+ ) {
stateDescriptionDeltas = state.stateDescription
}
}
@@ -574,11 +674,12 @@
setStateDescription(stateDescription.toString())
lastStateDescription = state.stateDescription
- accessibilityClass = if (state.state == Tile.STATE_UNAVAILABLE) {
- null
- } else {
- state.expandedAccessibilityClassName
- }
+ accessibilityClass =
+ if (state.state == Tile.STATE_UNAVAILABLE) {
+ null
+ } else {
+ state.expandedAccessibilityClassName
+ }
if (state is AdapterState) {
val newState = state.value
@@ -593,49 +694,51 @@
}
if (!Objects.equals(secondaryLabel.text, state.secondaryLabel)) {
secondaryLabel.text = state.secondaryLabel
- secondaryLabel.visibility = if (TextUtils.isEmpty(state.secondaryLabel)) {
- GONE
- } else {
- VISIBLE
- }
+ secondaryLabel.visibility =
+ if (TextUtils.isEmpty(state.secondaryLabel)) {
+ GONE
+ } else {
+ VISIBLE
+ }
}
// Colors
if (state.state != lastState || state.disabledByPolicy != lastDisabledByPolicy) {
singleAnimator.cancel()
mQsLogger?.logTileBackgroundColorUpdateIfInternetTile(
- state.spec,
- state.state,
- state.disabledByPolicy,
- getBackgroundColorForState(state.state, state.disabledByPolicy))
+ state.spec,
+ state.state,
+ state.disabledByPolicy,
+ getBackgroundColorForState(state.state, state.disabledByPolicy)
+ )
if (allowAnimations) {
singleAnimator.setValues(
- colorValuesHolder(
- BACKGROUND_NAME,
- backgroundColor,
- getBackgroundColorForState(state.state, state.disabledByPolicy)
- ),
- colorValuesHolder(
- LABEL_NAME,
- label.currentTextColor,
- getLabelColorForState(state.state, state.disabledByPolicy)
- ),
- colorValuesHolder(
- SECONDARY_LABEL_NAME,
- secondaryLabel.currentTextColor,
- getSecondaryLabelColorForState(state.state, state.disabledByPolicy)
- ),
- colorValuesHolder(
- CHEVRON_NAME,
- chevronView.imageTintList?.defaultColor ?: 0,
- getChevronColorForState(state.state, state.disabledByPolicy)
- ),
- colorValuesHolder(
- OVERLAY_NAME,
- backgroundOverlayColor,
- getOverlayColorForState(state.state)
- )
+ colorValuesHolder(
+ BACKGROUND_NAME,
+ backgroundColor,
+ getBackgroundColorForState(state.state, state.disabledByPolicy)
+ ),
+ colorValuesHolder(
+ LABEL_NAME,
+ label.currentTextColor,
+ getLabelColorForState(state.state, state.disabledByPolicy)
+ ),
+ colorValuesHolder(
+ SECONDARY_LABEL_NAME,
+ secondaryLabel.currentTextColor,
+ getSecondaryLabelColorForState(state.state, state.disabledByPolicy)
+ ),
+ colorValuesHolder(
+ CHEVRON_NAME,
+ chevronView.imageTintList?.defaultColor ?: 0,
+ getChevronColorForState(state.state, state.disabledByPolicy)
+ ),
+ colorValuesHolder(
+ OVERLAY_NAME,
+ backgroundOverlayColor,
+ getOverlayColorForState(state.state)
)
+ )
singleAnimator.start()
} else {
setAllColors(
@@ -658,25 +761,16 @@
lastIconTint = icon.getColor(state)
// Long-press effects
- if (state.handlesLongClick &&
- longPressEffect?.initializeEffect(longPressEffectDuration) == true) {
- // bind the long-press effect and set it as the touch listener
- if (!isLongPressEffectBound) {
- longPressEffectHandle =
- QSLongPressEffectViewBinder.bind(
- this,
- longPressEffect,
- state.spec,
- )
- }
+ if (
+ state.handlesLongClick &&
+ longPressEffect?.initializeEffect(longPressEffectDuration) == true
+ ) {
showRippleEffect = false
initializeLongPressProperties(measuredHeight, measuredWidth)
} else {
// Long-press effects might have been enabled before but the new state does not
// handle a long-press. In this case, we go back to the behaviour of a regular tile
// and clean-up the resources
- setOnTouchListener(null)
- unbindLongPressEffect()
showRippleEffect = isClickable
initialLongPressProperties = null
finalLongPressProperties = null
@@ -791,7 +885,7 @@
}
private fun getChevronColorForState(state: Int, disabledByPolicy: Boolean = false): Int =
- getSecondaryLabelColorForState(state, disabledByPolicy)
+ getSecondaryLabelColorForState(state, disabledByPolicy)
private fun getOverlayColorForState(state: Int): Int {
return when (state) {
@@ -828,16 +922,18 @@
// Dimensions change
val newHeight =
interpolateFloat(
- effectProgress,
- initialLongPressProperties?.height ?: 0f,
- finalLongPressProperties?.height ?: 0f,
- ).toInt()
+ effectProgress,
+ initialLongPressProperties?.height ?: 0f,
+ finalLongPressProperties?.height ?: 0f,
+ )
+ .toInt()
val newWidth =
interpolateFloat(
- effectProgress,
- initialLongPressProperties?.width ?: 0f,
- finalLongPressProperties?.width ?: 0f,
- ).toInt()
+ effectProgress,
+ initialLongPressProperties?.width ?: 0f,
+ finalLongPressProperties?.width ?: 0f,
+ )
+ .toInt()
val startingHeight = initialLongPressProperties?.height?.toInt() ?: 0
val startingWidth = initialLongPressProperties?.width?.toInt() ?: 0
@@ -898,11 +994,6 @@
)
}
- private fun unbindLongPressEffect() {
- longPressEffectHandle?.dispose()
- longPressEffectHandle = null
- }
-
private fun interpolateFloat(fraction: Float, start: Float, end: Float): Float =
start + fraction * (end - start)
@@ -964,12 +1055,13 @@
}
@VisibleForTesting
- internal fun getCurrentColors(): List<Int> = listOf(
+ internal fun getCurrentColors(): List<Int> =
+ listOf(
backgroundColor,
label.currentTextColor,
secondaryLabel.currentTextColor,
chevronView.imageTintList?.defaultColor ?: 0
- )
+ )
inner class StateChangeRunnable(private val state: QSTile.State) : Runnable {
override fun run() {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index 0327ec7..23faf7d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -73,7 +73,6 @@
import androidx.annotation.NonNull;
-import com.android.compose.animation.scene.SceneKey;
import com.android.internal.accessibility.dialog.AccessibilityButtonChooserActivity;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.AssistUtils;
@@ -99,12 +98,10 @@
import com.android.systemui.recents.OverviewProxyService.OverviewProxyListener;
import com.android.systemui.scene.domain.interactor.SceneInteractor;
import com.android.systemui.scene.shared.flag.SceneContainerFlag;
-import com.android.systemui.scene.shared.model.Scenes;
+import com.android.systemui.scene.shared.model.SceneFamilies;
import com.android.systemui.settings.DisplayTracker;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.shade.ShadeViewController;
-import com.android.systemui.shade.domain.interactor.ShadeInteractor;
-import com.android.systemui.shade.shared.model.ShadeMode;
import com.android.systemui.shared.recents.IOverviewProxy;
import com.android.systemui.shared.recents.ISystemUiProxy;
import com.android.systemui.shared.system.QuickStepContract;
@@ -158,7 +155,6 @@
private final ScreenPinningRequest mScreenPinningRequest;
private final NotificationShadeWindowController mStatusBarWinController;
private final Provider<SceneInteractor> mSceneInteractor;
- private final Provider<ShadeInteractor> mShadeInteractor;
private final Runnable mConnectionRunnable = () ->
internalConnectToCurrentUser("runnable: startConnectionToCurrentUser");
@@ -247,7 +243,7 @@
// Gesture was too short to be picked up by scene container touch
// handling; programmatically start the transition to shade scene.
mSceneInteractor.get().changeScene(
- getShadeSceneKey(),
+ SceneFamilies.NotifShade,
"short launcher swipe"
);
}
@@ -267,7 +263,7 @@
"trackpad swipe");
} else if (action == ACTION_UP) {
mSceneInteractor.get().changeScene(
- getShadeSceneKey(),
+ SceneFamilies.NotifShade,
"short trackpad swipe"
);
}
@@ -632,7 +628,6 @@
NotificationShadeWindowController statusBarWinController,
SysUiState sysUiState,
Provider<SceneInteractor> sceneInteractor,
- Provider<ShadeInteractor> shadeInteractor,
UserTracker userTracker,
WakefulnessLifecycle wakefulnessLifecycle,
UiEventLogger uiEventLogger,
@@ -659,7 +654,6 @@
mScreenPinningRequest = screenPinningRequest;
mStatusBarWinController = statusBarWinController;
mSceneInteractor = sceneInteractor;
- mShadeInteractor = shadeInteractor;
mUserTracker = userTracker;
mConnectionBackoffAttempts = 0;
mRecentsComponentName = ComponentName.unflattenFromString(context.getString(
@@ -925,12 +919,6 @@
}
}
- private SceneKey getShadeSceneKey() {
- return mShadeInteractor.get().getShadeMode().getValue() == ShadeMode.dual()
- ? Scenes.NotificationsShade
- : Scenes.Shade;
- }
-
private void notifyHomeRotationEnabled(boolean enabled) {
for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) {
mConnectionCallbacks.get(i).onHomeRotationEnabled(enabled);
diff --git a/packages/SystemUI/src/com/android/systemui/scene/KeyguardlessSceneContainerFrameworkModule.kt b/packages/SystemUI/src/com/android/systemui/scene/KeyguardlessSceneContainerFrameworkModule.kt
index da23936..323ca87 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/KeyguardlessSceneContainerFrameworkModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/KeyguardlessSceneContainerFrameworkModule.kt
@@ -20,6 +20,9 @@
import com.android.systemui.notifications.ui.composable.NotificationsShadeSessionModule
import com.android.systemui.scene.domain.SceneDomainModule
import com.android.systemui.scene.domain.interactor.WindowRootViewVisibilityInteractor
+import com.android.systemui.scene.domain.resolver.HomeSceneFamilyResolverModule
+import com.android.systemui.scene.domain.resolver.NotifShadeSceneFamilyResolverModule
+import com.android.systemui.scene.domain.resolver.QuickSettingsSceneFamilyResolverModule
import com.android.systemui.scene.domain.startable.SceneContainerStartable
import com.android.systemui.scene.domain.startable.ScrimStartable
import com.android.systemui.scene.shared.model.SceneContainerConfig
@@ -42,6 +45,11 @@
QuickSettingsSceneModule::class,
ShadeSceneModule::class,
SceneDomainModule::class,
+
+ // List SceneResolver modules for supported SceneFamilies
+ HomeSceneFamilyResolverModule::class,
+ NotifShadeSceneFamilyResolverModule::class,
+ QuickSettingsSceneFamilyResolverModule::class,
],
)
interface KeyguardlessSceneContainerFrameworkModule {
diff --git a/packages/SystemUI/src/com/android/systemui/scene/SceneContainerFrameworkModule.kt b/packages/SystemUI/src/com/android/systemui/scene/SceneContainerFrameworkModule.kt
index a0cf82a..4691eba 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/SceneContainerFrameworkModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/SceneContainerFrameworkModule.kt
@@ -21,6 +21,9 @@
import com.android.systemui.notifications.ui.composable.NotificationsShadeSessionModule
import com.android.systemui.scene.domain.SceneDomainModule
import com.android.systemui.scene.domain.interactor.WindowRootViewVisibilityInteractor
+import com.android.systemui.scene.domain.resolver.HomeSceneFamilyResolverModule
+import com.android.systemui.scene.domain.resolver.NotifShadeSceneFamilyResolverModule
+import com.android.systemui.scene.domain.resolver.QuickSettingsSceneFamilyResolverModule
import com.android.systemui.scene.domain.startable.SceneContainerStartable
import com.android.systemui.scene.domain.startable.ScrimStartable
import com.android.systemui.scene.shared.model.SceneContainerConfig
@@ -48,6 +51,11 @@
NotificationsShadeSceneModule::class,
NotificationsShadeSessionModule::class,
SceneDomainModule::class,
+
+ // List SceneResolver modules for supported SceneFamilies
+ HomeSceneFamilyResolverModule::class,
+ NotifShadeSceneFamilyResolverModule::class,
+ QuickSettingsSceneFamilyResolverModule::class,
],
)
interface SceneContainerFrameworkModule {
diff --git a/packages/SystemUI/src/com/android/systemui/scene/ShadelessSceneContainerFrameworkModule.kt b/packages/SystemUI/src/com/android/systemui/scene/ShadelessSceneContainerFrameworkModule.kt
index a326ec1..9a7eef8 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/ShadelessSceneContainerFrameworkModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/ShadelessSceneContainerFrameworkModule.kt
@@ -17,6 +17,7 @@
package com.android.systemui.scene
import com.android.systemui.scene.domain.SceneDomainModule
+import com.android.systemui.scene.domain.resolver.HomeSceneFamilyResolverModule
import com.android.systemui.scene.shared.model.SceneContainerConfig
import com.android.systemui.scene.shared.model.Scenes
import dagger.Module
@@ -31,6 +32,9 @@
GoneSceneModule::class,
LockscreenSceneModule::class,
SceneDomainModule::class,
+
+ // List SceneResolver modules for supported SceneFamilies
+ HomeSceneFamilyResolverModule::class,
],
)
object ShadelessSceneContainerFrameworkModule {
@@ -49,11 +53,12 @@
Scenes.Bouncer,
),
initialSceneKey = Scenes.Lockscreen,
- mapOf(
- Scenes.Gone to 0,
- Scenes.Lockscreen to 0,
- Scenes.Bouncer to 1,
- )
+ navigationDistances =
+ mapOf(
+ Scenes.Gone to 0,
+ Scenes.Lockscreen to 0,
+ Scenes.Bouncer to 1,
+ )
)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/SceneDomainModule.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/SceneDomainModule.kt
index 9b2a6dd..be792df 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/SceneDomainModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/SceneDomainModule.kt
@@ -16,14 +16,12 @@
package com.android.systemui.scene.domain
-import com.android.systemui.scene.domain.resolver.HomeSceneFamilyResolverModule
import com.android.systemui.scene.domain.resolver.SceneResolverModule
import dagger.Module
@Module(
includes =
[
- HomeSceneFamilyResolverModule::class,
SceneResolverModule::class,
]
)
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 2f66d6b..c98a49b 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
@@ -36,7 +36,9 @@
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.emitAll
import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
@@ -156,6 +158,28 @@
)
/**
+ * The amount of transition into or out of the given [scene].
+ *
+ * The value will be `0` if not in this scene or `1` when fully in the given scene.
+ */
+ fun transitionProgress(scene: SceneKey): Flow<Float> {
+ return transitionState.flatMapLatest { transition ->
+ when (transition) {
+ is ObservableTransitionState.Idle -> {
+ flowOf(if (transition.currentScene == scene) 1f else 0f)
+ }
+ is ObservableTransitionState.Transition -> {
+ when {
+ transition.toScene == scene -> transition.progress
+ transition.fromScene == scene -> transition.progress.map { 1f - it }
+ else -> flowOf(0f)
+ }
+ }
+ }
+ }
+ }
+
+ /**
* 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
@@ -217,7 +241,14 @@
loggingReason: String,
) {
val currentSceneKey = currentScene.value
- val resolvedScene = sceneFamilyResolvers.get()[toScene]?.resolvedScene?.value ?: toScene
+ val resolvedScene =
+ sceneFamilyResolvers.get()[toScene]?.let { familyResolver ->
+ if (familyResolver.includesScene(currentSceneKey)) {
+ return
+ } else {
+ familyResolver.resolvedScene.value
+ }
+ } ?: toScene
if (
!validateSceneChange(
from = currentSceneKey,
@@ -298,8 +329,9 @@
* Returns the [concrete scene][Scenes] for [sceneKey] if it is a [scene family][SceneFamilies],
* otherwise returns a singleton [Flow] containing [sceneKey].
*/
- fun resolveSceneFamily(sceneKey: SceneKey): Flow<SceneKey> =
- sceneFamilyResolvers.get()[sceneKey]?.resolvedScene ?: flowOf(sceneKey)
+ fun resolveSceneFamily(sceneKey: SceneKey): Flow<SceneKey> = flow {
+ emitAll(sceneFamilyResolvers.get()[sceneKey]?.resolvedScene ?: flowOf(sceneKey))
+ }
private fun isVisibleInternal(
raw: Boolean = repository.isVisible.value,
@@ -343,4 +375,12 @@
return from != to
}
+
+ /** Returns a flow indicating if the currently visible scene can be resolved from [family]. */
+ fun isCurrentSceneInFamily(family: SceneKey): Flow<Boolean> =
+ currentScene.map { currentScene -> isSceneInFamily(currentScene, family) }
+
+ /** Returns `true` if [scene] can be resolved from [family]. */
+ fun isSceneInFamily(scene: SceneKey, family: SceneKey): Boolean =
+ sceneFamilyResolvers.get()[family]?.includesScene(scene) == true
}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/resolver/HomeSceneFamilyResolver.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/resolver/HomeSceneFamilyResolver.kt
index f19929c..9e91b66 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/resolver/HomeSceneFamilyResolver.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/resolver/HomeSceneFamilyResolver.kt
@@ -51,25 +51,42 @@
override val resolvedScene: StateFlow<SceneKey> =
combine(
deviceEntryInteractor.canSwipeToEnter,
+ deviceEntryInteractor.isDeviceEntered,
deviceEntryInteractor.isUnlocked,
transform = ::homeScene,
)
.stateIn(
scope = applicationScope,
- started = SharingStarted.WhileSubscribed(),
+ started = SharingStarted.Eagerly,
initialValue =
homeScene(
deviceEntryInteractor.canSwipeToEnter.value,
+ deviceEntryInteractor.isDeviceEntered.value,
deviceEntryInteractor.isUnlocked.value,
)
)
- private fun homeScene(canSwipeToEnter: Boolean?, isUnlocked: Boolean): SceneKey =
+ override fun includesScene(scene: SceneKey): Boolean = scene in homeScenes
+
+ private fun homeScene(
+ canSwipeToEnter: Boolean?,
+ isDeviceEntered: Boolean,
+ isUnlocked: Boolean,
+ ): SceneKey =
when {
canSwipeToEnter == true -> Scenes.Lockscreen
- isUnlocked -> Scenes.Gone
- else -> Scenes.Lockscreen
+ !isDeviceEntered -> Scenes.Lockscreen
+ !isUnlocked -> Scenes.Lockscreen
+ else -> Scenes.Gone
}
+
+ companion object {
+ val homeScenes =
+ setOf(
+ Scenes.Gone,
+ Scenes.Lockscreen,
+ )
+ }
}
@Module
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/resolver/NotifShadeSceneFamilyResolver.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/resolver/NotifShadeSceneFamilyResolver.kt
new file mode 100644
index 0000000..99e554e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/resolver/NotifShadeSceneFamilyResolver.kt
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.scene.domain.resolver
+
+import com.android.compose.animation.scene.SceneKey
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.scene.shared.model.SceneFamilies
+import com.android.systemui.scene.shared.model.Scenes
+import com.android.systemui.shade.domain.interactor.ShadeInteractor
+import com.android.systemui.shade.shared.model.ShadeMode
+import dagger.Binds
+import dagger.Module
+import dagger.multibindings.IntoSet
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.stateIn
+
+@SysUISingleton
+class NotifShadeSceneFamilyResolver
+@Inject
+constructor(
+ @Application applicationScope: CoroutineScope,
+ shadeInteractor: ShadeInteractor,
+) : SceneResolver {
+ override val targetFamily: SceneKey = SceneFamilies.NotifShade
+
+ override val resolvedScene: StateFlow<SceneKey> =
+ shadeInteractor.shadeMode
+ .map(::notifShadeScene)
+ .stateIn(
+ applicationScope,
+ started = SharingStarted.Eagerly,
+ initialValue = notifShadeScene(shadeInteractor.shadeMode.value),
+ )
+
+ override fun includesScene(scene: SceneKey): Boolean = scene in notifShadeScenes
+
+ private fun notifShadeScene(shadeMode: ShadeMode) =
+ when (shadeMode) {
+ is ShadeMode.Single -> Scenes.Shade
+ is ShadeMode.Dual -> Scenes.NotificationsShade
+ is ShadeMode.Split -> Scenes.Shade
+ }
+
+ companion object {
+ val notifShadeScenes =
+ setOf(
+ Scenes.NotificationsShade,
+ Scenes.Shade,
+ )
+ }
+}
+
+@Module
+interface NotifShadeSceneFamilyResolverModule {
+ @Binds @IntoSet fun bindResolver(interactor: NotifShadeSceneFamilyResolver): SceneResolver
+}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/resolver/QuickSettingsSceneFamilyResolver.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/resolver/QuickSettingsSceneFamilyResolver.kt
new file mode 100644
index 0000000..2962a3e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/resolver/QuickSettingsSceneFamilyResolver.kt
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.scene.domain.resolver
+
+import com.android.compose.animation.scene.SceneKey
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.scene.shared.model.SceneFamilies
+import com.android.systemui.scene.shared.model.Scenes
+import com.android.systemui.shade.domain.interactor.ShadeInteractor
+import com.android.systemui.shade.shared.model.ShadeMode
+import dagger.Binds
+import dagger.Module
+import dagger.multibindings.IntoSet
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.stateIn
+
+@SysUISingleton
+class QuickSettingsSceneFamilyResolver
+@Inject
+constructor(
+ @Application applicationScope: CoroutineScope,
+ shadeInteractor: ShadeInteractor,
+) : SceneResolver {
+ override val targetFamily: SceneKey = SceneFamilies.QuickSettings
+
+ override val resolvedScene: StateFlow<SceneKey> =
+ shadeInteractor.shadeMode
+ .map(::quickSettingsScene)
+ .stateIn(
+ applicationScope,
+ started = SharingStarted.Eagerly,
+ initialValue = quickSettingsScene(shadeInteractor.shadeMode.value),
+ )
+
+ override fun includesScene(scene: SceneKey): Boolean = scene in quickSettingsScenes
+
+ private fun quickSettingsScene(shadeMode: ShadeMode) =
+ when (shadeMode) {
+ is ShadeMode.Single -> Scenes.QuickSettings
+ is ShadeMode.Dual -> Scenes.QuickSettingsShade
+ is ShadeMode.Split -> Scenes.Shade
+ }
+
+ companion object {
+ val quickSettingsScenes =
+ setOf(
+ Scenes.QuickSettings,
+ Scenes.QuickSettingsShade,
+ Scenes.Shade,
+ )
+ }
+}
+
+@Module
+interface QuickSettingsSceneFamilyResolverModule {
+ @Binds @IntoSet fun bindResolver(interactor: QuickSettingsSceneFamilyResolver): SceneResolver
+}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/resolver/SceneResolver.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/resolver/SceneResolver.kt
index 8372529..8d7247b 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/resolver/SceneResolver.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/resolver/SceneResolver.kt
@@ -29,6 +29,9 @@
/** The concrete scene that [targetFamily] is currently resolved to. */
val resolvedScene: StateFlow<SceneKey>
+
+ /** Returns `true` if [scene] can be resolved from [targetFamily]. */
+ fun includesScene(scene: SceneKey): Boolean
}
@Module
diff --git a/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/GoneSceneViewModel.kt b/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/GoneSceneViewModel.kt
index 99118bc..c34a6cd 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/GoneSceneViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/GoneSceneViewModel.kt
@@ -23,7 +23,7 @@
import com.android.compose.animation.scene.UserActionResult
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
-import com.android.systemui.scene.shared.model.Scenes
+import com.android.systemui.scene.shared.model.SceneFamilies
import com.android.systemui.scene.shared.model.TransitionKeys.ToSplitShade
import com.android.systemui.shade.domain.interactor.ShadeInteractor
import com.android.systemui.shade.shared.model.ShadeMode
@@ -43,39 +43,42 @@
) {
val destinationScenes: StateFlow<Map<UserAction, UserActionResult>> =
shadeInteractor.shadeMode
- .map { shadeMode -> destinationScenes(shadeMode = shadeMode) }
+ .map(::destinationScenes)
.stateIn(
scope = applicationScope,
started = SharingStarted.WhileSubscribed(),
- initialValue = destinationScenes(shadeMode = shadeInteractor.shadeMode.value)
+ initialValue =
+ destinationScenes(
+ shadeMode = shadeInteractor.shadeMode.value,
+ )
)
- private fun destinationScenes(shadeMode: ShadeMode): Map<UserAction, UserActionResult> {
+ private fun destinationScenes(
+ shadeMode: ShadeMode,
+ ): Map<UserAction, UserActionResult> {
return buildMap {
- if (shadeMode is ShadeMode.Single) {
- this[
+ if (
+ shadeMode is ShadeMode.Single ||
+ // TODO(b/338577208): Remove this once we add Dual Shade invocation zones.
+ shadeMode is ShadeMode.Dual
+ ) {
+ put(
Swipe(
pointerCount = 2,
fromSource = Edge.Top,
direction = SwipeDirection.Down,
- )] = UserActionResult(Scenes.QuickSettings)
+ ),
+ UserActionResult(SceneFamilies.QuickSettings)
+ )
}
- // TODO(b/338577208): Remove this once we add Dual Shade invocation zones.
- if (shadeMode is ShadeMode.Dual) {
- this[
- Swipe(
- pointerCount = 2,
- fromSource = Edge.Top,
- direction = SwipeDirection.Down,
- )] = UserActionResult(Scenes.QuickSettingsShade)
- }
-
- val downSceneKey =
- if (shadeMode is ShadeMode.Dual) Scenes.NotificationsShade else Scenes.Shade
- val downTransitionKey = ToSplitShade.takeIf { shadeMode is ShadeMode.Split }
- this[Swipe(direction = SwipeDirection.Down)] =
- UserActionResult(downSceneKey, downTransitionKey)
+ put(
+ Swipe(direction = SwipeDirection.Down),
+ UserActionResult(
+ SceneFamilies.NotifShade,
+ ToSplitShade.takeIf { shadeMode is ShadeMode.Split }
+ )
+ )
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
index c01b7b6..1df085b 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
@@ -227,7 +227,7 @@
bouncerViewBinder.bind(mView.findViewById(R.id.keyguard_bouncer_container));
collectFlow(mView, keyguardTransitionInteractor.transition(
- Edge.Companion.create(LOCKSCREEN, DREAMING)),
+ Edge.create(LOCKSCREEN, DREAMING)),
mLockscreenToDreamingTransition);
collectFlow(
mView,
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerSceneImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerSceneImpl.kt
index ac1f971..004db16 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerSceneImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerSceneImpl.kt
@@ -21,15 +21,12 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
-import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.dagger.ShadeTouchLog
import com.android.systemui.scene.domain.interactor.SceneInteractor
import com.android.systemui.scene.shared.model.SceneFamilies
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.scene.shared.model.TransitionKeys.SlightlyFasterShadeCollapse
import com.android.systemui.shade.ShadeController.ShadeVisibilityListener
import com.android.systemui.shade.domain.interactor.ShadeInteractor
-import com.android.systemui.shade.shared.model.ShadeMode
import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.statusbar.NotificationShadeWindowController
import com.android.systemui.statusbar.VibratorHelper
@@ -60,7 +57,6 @@
private val shadeInteractor: ShadeInteractor,
private val sceneInteractor: SceneInteractor,
private val notificationStackScrollLayout: NotificationStackScrollLayout,
- @ShadeTouchLog private val touchLog: LogBuffer,
private val vibratorHelper: VibratorHelper,
commandQueue: CommandQueue,
statusBarKeyguardViewManager: StatusBarKeyguardViewManager,
@@ -176,19 +172,14 @@
}
override fun expandToNotifications() {
- val shadeMode = shadeInteractor.shadeMode.value
sceneInteractor.changeScene(
- if (shadeMode is ShadeMode.Dual) Scenes.NotificationsShade else Scenes.Shade,
- "ShadeController.animateExpandShade"
+ SceneFamilies.NotifShade,
+ "ShadeController.animateExpandShade",
)
}
override fun expandToQs() {
- val shadeMode = shadeInteractor.shadeMode.value
- sceneInteractor.changeScene(
- if (shadeMode is ShadeMode.Dual) Scenes.QuickSettingsShade else Scenes.QuickSettings,
- "ShadeController.animateExpandQs"
- )
+ sceneInteractor.changeScene(SceneFamilies.QuickSettings, "ShadeController.animateExpandQs")
}
override fun setVisibilityListener(listener: ShadeVisibilityListener) {
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImpl.kt
index fe16fc0..d5b4f4d 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImpl.kt
@@ -21,25 +21,23 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.scene.domain.interactor.SceneInteractor
-import com.android.systemui.scene.shared.model.Scenes
+import com.android.systemui.scene.shared.model.SceneFamilies
import com.android.systemui.shade.data.repository.ShadeRepository
import com.android.systemui.shade.shared.model.ShadeMode
import com.android.systemui.statusbar.notification.stack.domain.interactor.SharedNotificationContainerInteractor
+import com.android.systemui.utils.coroutines.flow.flatMapLatestConflated
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
-import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
/** ShadeInteractor implementation for Scene Container. */
-@OptIn(ExperimentalCoroutinesApi::class)
@SysUISingleton
class ShadeInteractorSceneContainerImpl
@Inject
@@ -52,10 +50,11 @@
override val shadeMode: StateFlow<ShadeMode> = shadeRepository.shadeMode
override val shadeExpansion: StateFlow<Float> =
- sceneBasedExpansion(sceneInteractor, notificationsScene)
+ sceneBasedExpansion(sceneInteractor, SceneFamilies.NotifShade)
.stateIn(scope, SharingStarted.Eagerly, 0f)
- private val sceneBasedQsExpansion = sceneBasedExpansion(sceneInteractor, quickSettingsScene)
+ private val sceneBasedQsExpansion =
+ sceneBasedExpansion(sceneInteractor, SceneFamilies.QuickSettings)
override val qsExpansion: StateFlow<Float> =
combine(
@@ -78,23 +77,38 @@
.stateIn(scope, SharingStarted.Eagerly, false)
override val isQsBypassingShade: Flow<Boolean> =
- sceneInteractor.transitionState
- .map { state ->
- when (state) {
- is ObservableTransitionState.Idle -> false
- is ObservableTransitionState.Transition ->
- state.toScene == quickSettingsScene && state.fromScene != notificationsScene
- }
+ combine(
+ sceneInteractor.resolveSceneFamily(SceneFamilies.QuickSettings),
+ sceneInteractor.resolveSceneFamily(SceneFamilies.NotifShade),
+ ::Pair
+ )
+ .flatMapLatestConflated { (quickSettingsScene, notificationsScene) ->
+ sceneInteractor.transitionState
+ .map { state ->
+ when (state) {
+ is ObservableTransitionState.Idle -> false
+ is ObservableTransitionState.Transition ->
+ state.toScene == quickSettingsScene &&
+ state.fromScene != notificationsScene
+ }
+ }
+ .distinctUntilChanged()
}
.distinctUntilChanged()
override val isQsFullscreen: Flow<Boolean> =
- sceneInteractor.transitionState
- .map { state ->
- when (state) {
- is ObservableTransitionState.Idle -> state.currentScene == quickSettingsScene
- is ObservableTransitionState.Transition -> false
- }
+ sceneInteractor
+ .resolveSceneFamily(SceneFamilies.QuickSettings)
+ .flatMapLatestConflated { quickSettingsScene ->
+ sceneInteractor.transitionState
+ .map { state ->
+ when (state) {
+ is ObservableTransitionState.Idle ->
+ state.currentScene == quickSettingsScene
+ is ObservableTransitionState.Transition -> false
+ }
+ }
+ .distinctUntilChanged()
}
.distinctUntilChanged()
@@ -108,34 +122,39 @@
.stateIn(scope, SharingStarted.Eagerly, false)
override val isUserInteractingWithShade: Flow<Boolean> =
- sceneBasedInteracting(sceneInteractor, notificationsScene)
+ sceneBasedInteracting(sceneInteractor, SceneFamilies.NotifShade)
override val isUserInteractingWithQs: Flow<Boolean> =
- sceneBasedInteracting(sceneInteractor, quickSettingsScene)
+ sceneBasedInteracting(sceneInteractor, SceneFamilies.QuickSettings)
/**
* Returns a flow that uses scene transition progress to and from a scene that is pulled down
* from the top of the screen to a 0-1 expansion amount float.
*/
fun sceneBasedExpansion(sceneInteractor: SceneInteractor, sceneKey: SceneKey) =
- sceneInteractor.transitionState
- .flatMapLatest { state ->
- when (state) {
- is ObservableTransitionState.Idle ->
- if (state.currentScene == sceneKey) {
- flowOf(1f)
- } else {
- flowOf(0f)
+ sceneInteractor
+ .resolveSceneFamily(sceneKey)
+ .flatMapLatestConflated { resolvedSceneKey ->
+ sceneInteractor.transitionState
+ .flatMapLatestConflated { state ->
+ when (state) {
+ is ObservableTransitionState.Idle ->
+ if (state.currentScene == resolvedSceneKey) {
+ flowOf(1f)
+ } else {
+ flowOf(0f)
+ }
+ is ObservableTransitionState.Transition ->
+ if (state.toScene == resolvedSceneKey) {
+ state.progress
+ } else if (state.fromScene == resolvedSceneKey) {
+ state.progress.map { progress -> 1 - progress }
+ } else {
+ flowOf(0f)
+ }
}
- is ObservableTransitionState.Transition ->
- if (state.toScene == sceneKey) {
- state.progress
- } else if (state.fromScene == sceneKey) {
- state.progress.map { progress -> 1 - progress }
- } else {
- flowOf(0f)
- }
- }
+ }
+ .distinctUntilChanged()
}
.distinctUntilChanged()
@@ -145,29 +164,16 @@
*/
fun sceneBasedInteracting(sceneInteractor: SceneInteractor, sceneKey: SceneKey) =
sceneInteractor.transitionState
- .map { state ->
+ .flatMapLatestConflated { state ->
when (state) {
- is ObservableTransitionState.Idle -> false
+ is ObservableTransitionState.Idle -> flowOf(false)
is ObservableTransitionState.Transition ->
- state.isInitiatedByUserInput &&
- (state.toScene == sceneKey || state.fromScene == sceneKey)
+ sceneInteractor.resolveSceneFamily(sceneKey).map { resolvedSceneKey ->
+ state.isInitiatedByUserInput &&
+ (state.toScene == resolvedSceneKey ||
+ state.fromScene == resolvedSceneKey)
+ }
}
}
.distinctUntilChanged()
-
- private val notificationsScene: SceneKey
- get() =
- if (shadeMode.value is ShadeMode.Dual) {
- Scenes.NotificationsShade
- } else {
- Scenes.Shade
- }
-
- private val quickSettingsScene: SceneKey
- get() =
- if (shadeMode.value is ShadeMode.Dual) {
- Scenes.QuickSettingsShade
- } else {
- Scenes.QuickSettings
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeLockscreenInteractorImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeLockscreenInteractorImpl.kt
index e7fc18e..558f179 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeLockscreenInteractorImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeLockscreenInteractorImpl.kt
@@ -17,12 +17,11 @@
package com.android.systemui.shade.domain.interactor
import com.android.keyguard.LockIconViewController
-import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.scene.domain.interactor.SceneInteractor
+import com.android.systemui.scene.shared.model.SceneFamilies
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.shade.data.repository.ShadeRepository
-import com.android.systemui.shade.shared.model.ShadeMode
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.delay
@@ -31,7 +30,6 @@
class ShadeLockscreenInteractorImpl
@Inject
constructor(
- @Application private val applicationScope: CoroutineScope,
@Background private val backgroundScope: CoroutineScope,
private val shadeInteractor: ShadeInteractor,
private val sceneInteractor: SceneInteractor,
@@ -69,6 +67,7 @@
override fun setPulsing(pulsing: Boolean) {
// Now handled elsewhere. Do nothing.
}
+
override fun transitionToExpandedShade(delay: Long) {
backgroundScope.launch {
delay(delay)
@@ -98,12 +97,9 @@
}
private fun changeToShadeScene() {
- applicationScope.launch {
- val shadeMode = shadeInteractor.shadeMode.value
- sceneInteractor.changeScene(
- if (shadeMode is ShadeMode.Dual) Scenes.NotificationsShade else Scenes.Shade,
- "ShadeLockscreenInteractorImpl.expandToNotifications",
- )
- }
+ sceneInteractor.changeScene(
+ SceneFamilies.NotifShade,
+ "ShadeLockscreenInteractorImpl.expandToNotifications",
+ )
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
index 2e87a5b..ee2c9cc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
@@ -38,6 +38,7 @@
import android.view.ViewGroup
import androidx.annotation.VisibleForTesting
import com.android.keyguard.KeyguardUpdateMonitor
+import com.android.keyguard.KeyguardUpdateMonitorCallback
import com.android.settingslib.Utils
import com.android.systemui.Dumpable
import com.android.systemui.Flags.smartspaceLockscreenViewmodel
@@ -53,6 +54,7 @@
import com.android.systemui.plugins.BcSmartspaceDataPlugin
import com.android.systemui.plugins.BcSmartspaceDataPlugin.SmartspaceTargetListener
import com.android.systemui.plugins.BcSmartspaceDataPlugin.SmartspaceView
+import com.android.systemui.plugins.BcSmartspaceDataPlugin.TimeChangedDelegate
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.plugins.clocks.WeatherData
import com.android.systemui.plugins.statusbar.StatusBarStateController
@@ -411,6 +413,7 @@
val ssView = plugin.getView(parent)
configPlugin?.let { ssView.registerConfigProvider(it) }
ssView.setUiSurface(BcSmartspaceDataPlugin.UI_SURFACE_LOCK_SCREEN_AOD)
+ ssView.setTimeChangedDelegate(SmartspaceTimeChangedDelegate(keyguardUpdateMonitor))
ssView.registerDataProvider(plugin)
ssView.setIntentStarter(object : BcSmartspaceDataPlugin.IntentStarter {
@@ -682,5 +685,28 @@
}
}
}
+
+ private class SmartspaceTimeChangedDelegate(
+ private val keyguardUpdateMonitor: KeyguardUpdateMonitor
+ ) : TimeChangedDelegate {
+ private var keyguardUpdateMonitorCallback: KeyguardUpdateMonitorCallback? = null
+ override fun register(callback: Runnable) {
+ if (keyguardUpdateMonitorCallback != null) {
+ unregister()
+ }
+ keyguardUpdateMonitorCallback = object : KeyguardUpdateMonitorCallback() {
+ override fun onTimeChanged() {
+ callback.run()
+ }
+ }
+ keyguardUpdateMonitor.registerCallback(keyguardUpdateMonitorCallback)
+ callback.run()
+ }
+
+ override fun unregister() {
+ keyguardUpdateMonitor.removeCallback(keyguardUpdateMonitorCallback)
+ keyguardUpdateMonitorCallback = null
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/AvalancheProvider.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/AvalancheProvider.kt
index c29d700..a8fd082 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/AvalancheProvider.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/AvalancheProvider.kt
@@ -24,6 +24,7 @@
import com.android.internal.logging.UiEventLogger
import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.statusbar.notification.interruption.AvalancheSuppressor.AvalancheEvent
import javax.inject.Inject
// Class to track avalanche trigger event time.
@@ -31,37 +32,41 @@
class AvalancheProvider
@Inject
constructor(
- private val broadcastDispatcher: BroadcastDispatcher,
- private val logger: VisualInterruptionDecisionLogger,
- private val uiEventLogger: UiEventLogger,
+ private val broadcastDispatcher: BroadcastDispatcher,
+ private val logger: VisualInterruptionDecisionLogger,
+ private val uiEventLogger: UiEventLogger,
) {
val TAG = "AvalancheProvider"
val timeoutMs = 120000
var startTime: Long = 0L
- private val avalancheTriggerIntents = mutableSetOf(
+ private val avalancheTriggerIntents =
+ mutableSetOf(
Intent.ACTION_AIRPLANE_MODE_CHANGED,
Intent.ACTION_BOOT_COMPLETED,
Intent.ACTION_MANAGED_PROFILE_AVAILABLE,
Intent.ACTION_USER_SWITCHED
- )
+ )
- private val broadcastReceiver: BroadcastReceiver = object : BroadcastReceiver() {
- override fun onReceive(context: Context, intent: Intent) {
- if (intent.action in avalancheTriggerIntents) {
+ private val broadcastReceiver: BroadcastReceiver =
+ object : BroadcastReceiver() {
+ override fun onReceive(context: Context, intent: Intent) {
+ if (intent.action in avalancheTriggerIntents) {
- // Ignore when airplane mode turned on
- if (intent.action == Intent.ACTION_AIRPLANE_MODE_CHANGED
- && intent.getBooleanExtra(/* name= */ "state", /* defaultValue */ false)) {
- Log.d(TAG, "broadcastReceiver: ignore airplane mode on")
- return
+ // Ignore when airplane mode turned on
+ if (
+ intent.action == Intent.ACTION_AIRPLANE_MODE_CHANGED &&
+ intent.getBooleanExtra(/* name= */ "state", /* defaultValue */ false)
+ ) {
+ Log.d(TAG, "broadcastReceiver: ignore airplane mode on")
+ return
+ }
+ Log.d(TAG, "broadcastReceiver received intent.action=" + intent.action)
+ uiEventLogger.log(AvalancheEvent.AVALANCHE_SUPPRESSOR_RECEIVED_TRIGGERING_EVENT)
+ startTime = System.currentTimeMillis()
}
- Log.d(TAG, "broadcastReceiver received intent.action=" + intent.action)
- uiEventLogger.log(AvalancheSuppressor.AvalancheEvent.START);
- startTime = System.currentTimeMillis()
}
}
- }
fun register() {
val intentFilter = IntentFilter()
@@ -70,4 +75,4 @@
}
broadcastDispatcher.registerReceiver(broadcastReceiver, intentFilter)
}
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/CommonVisualInterruptionSuppressors.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/CommonVisualInterruptionSuppressors.kt
index f84b5f4..367aaad 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/CommonVisualInterruptionSuppressors.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/CommonVisualInterruptionSuppressors.kt
@@ -270,32 +270,26 @@
}
enum class AvalancheEvent(private val id: Int) : UiEventLogger.UiEventEnum {
- @UiEvent(
- doc =
- "An avalanche event occurred but this notification was suppressed by a " +
- "non-avalanche suppressor."
- )
- START(1802),
- @UiEvent(doc = "HUN was suppressed in avalanche.") SUPPRESS(1803),
- @UiEvent(doc = "HUN allowed during avalanche because it is high priority.")
- ALLOW_CONVERSATION_AFTER_AVALANCHE(1804),
- @UiEvent(doc = "HUN allowed during avalanche because it is a high priority conversation.")
- ALLOW_HIGH_PRIORITY_CONVERSATION_ANY_TIME(1805),
- @UiEvent(doc = "HUN allowed during avalanche because it is a call.") ALLOW_CALLSTYLE(1806),
+ @UiEvent(doc = "An avalanche event occurred, and a suppression period will start now.")
+ AVALANCHE_SUPPRESSOR_RECEIVED_TRIGGERING_EVENT(1824),
+ @UiEvent(doc = "HUN was suppressed in avalanche.")
+ AVALANCHE_SUPPRESSOR_HUN_SUPPRESSED(1825),
+ @UiEvent(doc = "HUN allowed during avalanche because conversation newer than the trigger.")
+ AVALANCHE_SUPPRESSOR_HUN_ALLOWED_NEW_CONVERSATION(1826),
+ @UiEvent(doc = "HUN allowed during avalanche because it is a priority conversation.")
+ AVALANCHE_SUPPRESSOR_HUN_ALLOWED_PRIORITY_CONVERSATION(1827),
+ @UiEvent(doc = "HUN allowed during avalanche because it is a CallStyle notification.")
+ AVALANCHE_SUPPRESSOR_HUN_ALLOWED_CALL_STYLE(1828),
+ @UiEvent(doc = "HUN allowed during avalanche because it is a reminder notification.")
+ AVALANCHE_SUPPRESSOR_HUN_ALLOWED_CATEGORY_REMINDER(1829),
@UiEvent(doc = "HUN allowed during avalanche because it is a calendar notification.")
- ALLOW_CATEGORY_REMINDER(1807),
- @UiEvent(doc = "HUN allowed during avalanche because it is a calendar notification.")
- ALLOW_CATEGORY_EVENT(1808),
- @UiEvent(
- doc =
- "HUN allowed during avalanche because it has a full screen intent and " +
- "the full screen intent permission is granted."
- )
- ALLOW_FSI_WITH_PERMISSION_ON(1809),
+ AVALANCHE_SUPPRESSOR_HUN_ALLOWED_CATEGORY_EVENT(1830),
+ @UiEvent(doc = "HUN allowed during avalanche because it has FSI.")
+ AVALANCHE_SUPPRESSOR_HUN_ALLOWED_FSI_WITH_PERMISSION(1831),
@UiEvent(doc = "HUN allowed during avalanche because it is colorized.")
- ALLOW_COLORIZED(1810),
+ AVALANCHE_SUPPRESSOR_HUN_ALLOWED_COLORIZED(1832),
@UiEvent(doc = "HUN allowed during avalanche because it is an emergency notification.")
- ALLOW_EMERGENCY(1811);
+ AVALANCHE_SUPPRESSOR_HUN_ALLOWED_EMERGENCY(1833);
override fun getId(): Int {
return id
@@ -323,46 +317,46 @@
entry.ranking.isConversation &&
entry.sbn.notification.getWhen() > avalancheProvider.startTime
) {
- uiEventLogger.log(AvalancheEvent.ALLOW_CONVERSATION_AFTER_AVALANCHE)
+ uiEventLogger.log(AvalancheEvent.AVALANCHE_SUPPRESSOR_HUN_ALLOWED_NEW_CONVERSATION)
return State.ALLOW_CONVERSATION_AFTER_AVALANCHE
}
if (entry.channel?.isImportantConversation == true) {
- uiEventLogger.log(AvalancheEvent.ALLOW_HIGH_PRIORITY_CONVERSATION_ANY_TIME)
+ uiEventLogger.log(AvalancheEvent.AVALANCHE_SUPPRESSOR_HUN_ALLOWED_PRIORITY_CONVERSATION)
return State.ALLOW_HIGH_PRIORITY_CONVERSATION_ANY_TIME
}
if (entry.sbn.notification.isStyle(Notification.CallStyle::class.java)) {
- uiEventLogger.log(AvalancheEvent.ALLOW_CALLSTYLE)
+ uiEventLogger.log(AvalancheEvent.AVALANCHE_SUPPRESSOR_HUN_ALLOWED_CALL_STYLE)
return State.ALLOW_CALLSTYLE
}
if (entry.sbn.notification.category == CATEGORY_REMINDER) {
- uiEventLogger.log(AvalancheEvent.ALLOW_CATEGORY_REMINDER)
+ uiEventLogger.log(AvalancheEvent.AVALANCHE_SUPPRESSOR_HUN_ALLOWED_CATEGORY_REMINDER)
return State.ALLOW_CATEGORY_REMINDER
}
if (entry.sbn.notification.category == CATEGORY_EVENT) {
- uiEventLogger.log(AvalancheEvent.ALLOW_CATEGORY_EVENT)
+ uiEventLogger.log(AvalancheEvent.AVALANCHE_SUPPRESSOR_HUN_ALLOWED_CATEGORY_EVENT)
return State.ALLOW_CATEGORY_EVENT
}
if (entry.sbn.notification.fullScreenIntent != null) {
- uiEventLogger.log(AvalancheEvent.ALLOW_FSI_WITH_PERMISSION_ON)
+ uiEventLogger.log(AvalancheEvent.AVALANCHE_SUPPRESSOR_HUN_ALLOWED_FSI_WITH_PERMISSION)
return State.ALLOW_FSI_WITH_PERMISSION_ON
}
if (entry.sbn.notification.isColorized) {
- uiEventLogger.log(AvalancheEvent.ALLOW_COLORIZED)
+ uiEventLogger.log(AvalancheEvent.AVALANCHE_SUPPRESSOR_HUN_ALLOWED_COLORIZED)
return State.ALLOW_COLORIZED
}
if (
packageManager.checkPermission(RECEIVE_EMERGENCY_BROADCAST, entry.sbn.packageName) ==
PERMISSION_GRANTED
) {
- uiEventLogger.log(AvalancheEvent.ALLOW_EMERGENCY)
+ uiEventLogger.log(AvalancheEvent.AVALANCHE_SUPPRESSOR_HUN_ALLOWED_EMERGENCY)
return State.ALLOW_EMERGENCY
}
- uiEventLogger.log(AvalancheEvent.SUPPRESS)
+ uiEventLogger.log(AvalancheEvent.AVALANCHE_SUPPRESSOR_HUN_SUPPRESSED)
return State.SUPPRESS
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index fe22cc6..b77321b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -833,6 +833,23 @@
int y = 0;
drawDebugInfo(canvas, y, Color.RED, /* label= */ "y = " + y);
+ if (SceneContainerFlag.isEnabled()) {
+ y = (int) mScrollViewFields.getStackTop();
+ drawDebugInfo(canvas, y, Color.RED, /* label= */ "getStackTop() = " + y);
+
+ y = (int) mScrollViewFields.getStackBottom();
+ drawDebugInfo(canvas, y, Color.MAGENTA, /* label= */ "getStackBottom() = " + y);
+
+ y = (int) mScrollViewFields.getHeadsUpTop();
+ drawDebugInfo(canvas, y, Color.GREEN, /* label= */ "getHeadsUpTop() = " + y);
+
+ y += getTopHeadsUpHeight();
+ drawDebugInfo(canvas, y, Color.BLUE,
+ /* label= */ "getHeadsUpTop() + getTopHeadsUpHeight() = " + y);
+
+ return; // the rest of the fields are not important in Flexiglass
+ }
+
y = getTopPadding();
drawDebugInfo(canvas, y, Color.RED, /* label= */ "getTopPadding() = " + y);
@@ -3471,6 +3488,7 @@
}
if (isUpOrCancel) {
+ mScrollViewFields.sendCurrentGestureOverscroll(false);
setIsBeingDragged(false);
}
return false;
@@ -3606,7 +3624,6 @@
if (mIsBeingDragged) {
// Defer actual scrolling to the scene framework if enabled
if (SceneContainerFlag.isEnabled()) {
- setIsBeingDragged(false);
return false;
}
// Scroll to follow the motion event
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt
index e90a64a..cf5a562 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt
@@ -24,6 +24,7 @@
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.scene.domain.interactor.SceneInteractor
import com.android.systemui.scene.shared.flag.SceneContainerFlag
+import com.android.systemui.scene.shared.model.SceneFamilies
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.shade.domain.interactor.ShadeInteractor
import com.android.systemui.shade.shared.model.ShadeMode
@@ -36,11 +37,9 @@
import dagger.Lazy
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flowOf
-import kotlinx.coroutines.flow.map
/** ViewModel which represents the state of the NSSL/Controller in the world of flexiglass */
@SysUISingleton
@@ -50,7 +49,7 @@
dumpManager: DumpManager,
stackAppearanceInteractor: NotificationStackAppearanceInteractor,
shadeInteractor: ShadeInteractor,
- sceneInteractor: SceneInteractor,
+ private val sceneInteractor: SceneInteractor,
// TODO(b/336364825) Remove Lazy when SceneContainerFlag is released -
// while the flag is off, creating this object too early results in a crash
keyguardInteractor: Lazy<KeyguardInteractor>,
@@ -63,9 +62,11 @@
val expandFraction: Flow<Float> =
combine(
shadeInteractor.shadeExpansion,
+ shadeInteractor.shadeMode,
shadeInteractor.qsExpansion,
sceneInteractor.transitionState,
- ) { shadeExpansion, qsExpansion, transitionState ->
+ sceneInteractor.resolveSceneFamily(SceneFamilies.QuickSettings),
+ ) { shadeExpansion, shadeMode, qsExpansion, transitionState, quickSettingsScene ->
when (transitionState) {
is ObservableTransitionState.Idle -> {
if (transitionState.currentScene == Scenes.Lockscreen) {
@@ -76,16 +77,16 @@
}
is ObservableTransitionState.Transition -> {
if (
- (transitionState.fromScene == notificationsScene &&
+ (transitionState.fromScene in SceneFamilies.NotifShade &&
transitionState.toScene == quickSettingsScene) ||
- (transitionState.fromScene == quickSettingsScene &&
- transitionState.toScene == notificationsScene)
+ (transitionState.fromScene in quickSettingsScene &&
+ transitionState.toScene in SceneFamilies.NotifShade)
) {
1f
} else if (
- (transitionState.fromScene == Scenes.Gone ||
- transitionState.fromScene == Scenes.Lockscreen) &&
- transitionState.toScene == quickSettingsScene
+ shadeMode != ShadeMode.Split &&
+ transitionState.fromScene in SceneFamilies.Home &&
+ transitionState.toScene in quickSettingsScene
) {
// during QS expansion, increase fraction at same rate as scrim alpha,
// but start when scrim alpha is at EXPANSION_FOR_DELAYED_STACK_FADE_IN.
@@ -101,6 +102,9 @@
.distinctUntilChanged()
.dumpWhileCollecting("expandFraction")
+ private operator fun SceneKey.contains(scene: SceneKey) =
+ sceneInteractor.isSceneInFamily(scene, this)
+
/** The bounds of the notification stack in the current scene. */
private val shadeScrimClipping: Flow<ShadeScrimClipping?> =
combine(
@@ -151,8 +155,8 @@
/** Whether the notification stack is scrollable or not. */
val isScrollable: Flow<Boolean> =
- sceneInteractor.currentScene
- .map { it == notificationsScene }
+ sceneInteractor
+ .isCurrentSceneInFamily(SceneFamilies.NotifShade)
.dumpWhileCollecting("isScrollable")
/** Whether the notification stack is displayed in doze mode. */
@@ -163,22 +167,4 @@
keyguardInteractor.get().isDozing.dumpWhileCollecting("isDozing")
}
}
-
- private val shadeMode: StateFlow<ShadeMode> = shadeInteractor.shadeMode
-
- private val notificationsScene: SceneKey
- get() =
- if (shadeMode.value is ShadeMode.Dual) {
- Scenes.NotificationsShade
- } else {
- Scenes.Shade
- }
-
- private val quickSettingsScene: SceneKey
- get() =
- if (shadeMode.value is ShadeMode.Dual) {
- Scenes.QuickSettingsShade
- } else {
- Scenes.QuickSettings
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
index 6dfaec9..6a8c43a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
@@ -441,7 +441,7 @@
anyOf(
*toFlowArray(statesForHiddenKeyguard) { state ->
keyguardTransitionInteractor
- .transitionStepsToState(state)
+ .transition(Edge.create(to = state))
.map { it.value > 0f && it.transitionState == RUNNING }
.onStart { emit(false) }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LegacyActivityStarterInternalImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LegacyActivityStarterInternalImpl.kt
index fc29eab..e5fc4e2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LegacyActivityStarterInternalImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LegacyActivityStarterInternalImpl.kt
@@ -555,7 +555,12 @@
override fun onTransitionAnimationStart(isExpandingFullyAbove: Boolean) {
super.onTransitionAnimationStart(isExpandingFullyAbove)
-
+ if (communalHub()) {
+ communalSceneInteractor.snapToScene(
+ CommunalScenes.Blank,
+ ActivityTransitionAnimator.TIMINGS.totalDuration
+ )
+ }
// Double check that the keyguard is still showing and not going
// away, but if so set the keyguard occluded. Typically, WM will let
// KeyguardViewMediator know directly, but we're overriding that to
@@ -581,9 +586,6 @@
// collapse the shade (or at least run the post collapse runnables)
// later on.
centralSurfaces?.setIsLaunchingActivityOverLockscreen(false, false)
- if (communalHub()) {
- communalSceneInteractor.snapToScene(CommunalScenes.Blank)
- }
delegate.onTransitionAnimationEnd(isExpandingFullyAbove)
}
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 db4f0af..b40bf56 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -73,6 +73,7 @@
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
import com.android.systemui.keyguard.domain.interactor.WindowManagerLockscreenVisibilityInteractor;
import com.android.systemui.keyguard.shared.model.DismissAction;
+import com.android.systemui.keyguard.shared.model.Edge;
import com.android.systemui.keyguard.shared.model.KeyguardDone;
import com.android.systemui.keyguard.shared.model.KeyguardState;
import com.android.systemui.keyguard.shared.model.TransitionStep;
@@ -508,8 +509,8 @@
mListenForCanShowAlternateBouncer = null;
if (!DeviceEntryUdfpsRefactor.isEnabled()) {
mListenForAlternateBouncerTransitionSteps = mJavaAdapter.alwaysCollectFlow(
- mKeyguardTransitionInteractor.transitionStepsFromState(
- KeyguardState.ALTERNATE_BOUNCER),
+ mKeyguardTransitionInteractor
+ .transition(Edge.create(KeyguardState.ALTERNATE_BOUNCER)),
this::consumeFromAlternateBouncerTransitionSteps
);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/data/DeviceBasedSatelliteRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/data/DeviceBasedSatelliteRepository.kt
index d38e834..1d08f2b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/data/DeviceBasedSatelliteRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/data/DeviceBasedSatelliteRepository.kt
@@ -25,6 +25,9 @@
* given mobile data subscription.
*/
interface DeviceBasedSatelliteRepository {
+ /** The current status of satellite provisioning. If not false, we don't want to show an icon */
+ val isSatelliteProvisioned: StateFlow<Boolean>
+
/** See [SatelliteConnectionState] for available states */
val connectionState: StateFlow<SatelliteConnectionState>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/data/DeviceBasedSatelliteRepositorySwitcher.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/data/DeviceBasedSatelliteRepositorySwitcher.kt
index 6b1bc65..58c30e0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/data/DeviceBasedSatelliteRepositorySwitcher.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/data/DeviceBasedSatelliteRepositorySwitcher.kt
@@ -97,6 +97,11 @@
}
.stateIn(scope, SharingStarted.WhileSubscribed(), realImpl)
+ override val isSatelliteProvisioned: StateFlow<Boolean> =
+ activeRepo
+ .flatMapLatest { it.isSatelliteProvisioned }
+ .stateIn(scope, SharingStarted.WhileSubscribed(), realImpl.isSatelliteProvisioned.value)
+
override val connectionState: StateFlow<SatelliteConnectionState> =
activeRepo
.flatMapLatest { it.connectionState }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/data/demo/DemoDeviceBasedSatelliteRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/data/demo/DemoDeviceBasedSatelliteRepository.kt
index 56034f0..6ad295e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/data/demo/DemoDeviceBasedSatelliteRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/data/demo/DemoDeviceBasedSatelliteRepository.kt
@@ -36,6 +36,7 @@
) : DeviceBasedSatelliteRepository {
private var demoCommandJob: Job? = null
+ override val isSatelliteProvisioned = MutableStateFlow(true)
override val connectionState = MutableStateFlow(SatelliteConnectionState.Unknown)
override val signalStrength = MutableStateFlow(0)
override val isSatelliteAllowedForCurrentLocation = MutableStateFlow(true)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/DeviceBasedSatelliteRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/DeviceBasedSatelliteRepositoryImpl.kt
index 1449e53..ec3af87 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/DeviceBasedSatelliteRepositoryImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/DeviceBasedSatelliteRepositoryImpl.kt
@@ -23,6 +23,7 @@
import android.telephony.satellite.SatelliteManager
import android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_SUCCESS
import android.telephony.satellite.SatelliteModemStateCallback
+import android.telephony.satellite.SatelliteProvisionStateCallback
import android.telephony.satellite.SatelliteSupportedStateCallback
import androidx.annotation.VisibleForTesting
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
@@ -337,6 +338,43 @@
}
}
+ override val isSatelliteProvisioned: StateFlow<Boolean> =
+ satelliteSupport
+ .whenSupported(
+ supported = ::satelliteProvisioned,
+ orElse = flowOf(false),
+ retrySignal = telephonyProcessCrashedEvent,
+ )
+ .stateIn(scope, SharingStarted.WhileSubscribed(), false)
+
+ private fun satelliteProvisioned(sm: SupportedSatelliteManager): Flow<Boolean> =
+ conflatedCallbackFlow {
+ val callback = SatelliteProvisionStateCallback { provisioned ->
+ logBuffer.i {
+ "onSatelliteProvisionStateChanged: " +
+ if (provisioned) "provisioned" else "not provisioned"
+ }
+ trySend(provisioned)
+ }
+
+ var registered = false
+ try {
+ sm.registerForProvisionStateChanged(
+ bgDispatcher.asExecutor(),
+ callback,
+ )
+ registered = true
+ } catch (e: Exception) {
+ logBuffer.e("error registering for provisioning state callback", e)
+ }
+
+ awaitClose {
+ if (registered) {
+ sm.unregisterForProvisionStateChanged(callback)
+ }
+ }
+ }
+
/**
* Signal that we should start polling [checkIsSatelliteAllowed]. We only need to poll if there
* are active listeners to [isSatelliteAllowedForCurrentLocation]
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractor.kt
index b66ace6..03f88c7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractor.kt
@@ -27,7 +27,6 @@
import com.android.systemui.statusbar.pipeline.satellite.shared.model.SatelliteConnectionState
import com.android.systemui.statusbar.pipeline.wifi.domain.interactor.WifiInteractor
import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel
-import com.android.systemui.statusbar.policy.domain.interactor.DeviceProvisioningInteractor
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -45,7 +44,6 @@
constructor(
val repo: DeviceBasedSatelliteRepository,
iconsInteractor: MobileIconsInteractor,
- deviceProvisioningInteractor: DeviceProvisioningInteractor,
wifiInteractor: WifiInteractor,
@Application scope: CoroutineScope,
@DeviceBasedSatelliteInputLog private val logBuffer: LogBuffer,
@@ -78,7 +76,7 @@
}
.stateIn(scope, SharingStarted.WhileSubscribed(), 0)
- val isDeviceProvisioned: Flow<Boolean> = deviceProvisioningInteractor.isDeviceProvisioned
+ val isSatelliteProvisioned = repo.isSatelliteProvisioned
val isWifiActive: Flow<Boolean> =
wifiInteractor.wifiNetwork.map { it is WifiNetworkModel.Active }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/ui/viewmodel/DeviceBasedSatelliteViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/ui/viewmodel/DeviceBasedSatelliteViewModel.kt
index 0ed1b9b..48278d4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/ui/viewmodel/DeviceBasedSatelliteViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/ui/viewmodel/DeviceBasedSatelliteViewModel.kt
@@ -79,11 +79,11 @@
} else {
combine(
interactor.isSatelliteAllowed,
- interactor.isDeviceProvisioned,
+ interactor.isSatelliteProvisioned,
interactor.isWifiActive,
airplaneModeRepository.isAirplaneMode
- ) { isSatelliteAllowed, isDeviceProvisioned, isWifiActive, isAirplaneMode ->
- isSatelliteAllowed && isDeviceProvisioned && !isWifiActive && !isAirplaneMode
+ ) { isSatelliteAllowed, isSatelliteProvisioned, isWifiActive, isAirplaneMode ->
+ isSatelliteAllowed && isSatelliteProvisioned && !isWifiActive && !isAirplaneMode
}
}
}
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 a972985..32774e0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AvalancheController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AvalancheController.kt
@@ -35,10 +35,7 @@
@SysUISingleton
class AvalancheController
@Inject
-constructor(
- dumpManager: DumpManager,
- private val uiEventLogger: UiEventLogger
-) : Dumpable {
+constructor(dumpManager: DumpManager, private val uiEventLogger: UiEventLogger) : Dumpable {
private val tag = "AvalancheController"
private val debug = Compile.IS_DEBUG && Log.isLoggable(tag, Log.DEBUG)
@@ -69,14 +66,11 @@
@VisibleForTesting var debugDropSet: MutableSet<HeadsUpEntry> = HashSet()
enum class ThrottleEvent(private val id: Int) : UiEventLogger.UiEventEnum {
- @UiEvent(doc = "HUN was shown.")
- SHOWN(1812),
-
+ @UiEvent(doc = "HUN was shown.") AVALANCHE_THROTTLING_HUN_SHOWN(1821),
@UiEvent(doc = "HUN was dropped to show higher priority HUNs.")
- DROPPED(1813),
-
+ AVALANCHE_THROTTLING_HUN_DROPPED(1822),
@UiEvent(doc = "HUN was removed while waiting to show.")
- REMOVED(1814);
+ AVALANCHE_THROTTLING_HUN_REMOVED(1823);
override fun getId(): Int {
return id
@@ -97,7 +91,7 @@
runnable.run()
return
}
- log { "\n "}
+ log { "\n " }
val fn = "$label => AvalancheController.update ${getKey(entry)}"
if (entry == null) {
log { "Entry is NULL, stop update." }
@@ -129,9 +123,10 @@
// HeadsUpEntry.updateEntry recursively calls AvalancheController#update
// and goes to the isShowing case above
headsUpEntryShowing!!.updateEntry(
- /* updatePostTime= */ false,
- /* updateEarliestRemovalTime= */ false,
- /* reason= */ "avalanche duration update")
+ /* updatePostTime= */ false,
+ /* updateEarliestRemovalTime= */ false,
+ /* reason= */ "avalanche duration update"
+ )
}
}
logState("after $fn")
@@ -152,7 +147,7 @@
runnable.run()
return
}
- log { "\n "}
+ log { "\n " }
val fn = "$label => AvalancheController.delete " + getKey(entry)
if (entry == null) {
log { "$fn => entry NULL, running runnable" }
@@ -163,7 +158,7 @@
log { "$fn => remove from next" }
if (entry in nextMap) nextMap.remove(entry)
if (entry in nextList) nextList.remove(entry)
- uiEventLogger.log(ThrottleEvent.REMOVED)
+ uiEventLogger.log(ThrottleEvent.AVALANCHE_THROTTLING_HUN_REMOVED)
} else if (entry in debugDropSet) {
log { "$fn => remove from dropset" }
debugDropSet.remove(entry)
@@ -287,7 +282,7 @@
private fun showNow(entry: HeadsUpEntry, runnableList: MutableList<Runnable>) {
log { "SHOW: " + getKey(entry) }
- uiEventLogger.log(ThrottleEvent.SHOWN)
+ uiEventLogger.log(ThrottleEvent.AVALANCHE_THROTTLING_HUN_SHOWN)
headsUpEntryShowing = entry
runnableList.forEach {
@@ -318,7 +313,7 @@
// Log dropped HUNs
for (e in listToDrop) {
- uiEventLogger.log(ThrottleEvent.DROPPED)
+ uiEventLogger.log(ThrottleEvent.AVALANCHE_THROTTLING_HUN_DROPPED)
}
if (debug) {
diff --git a/packages/SystemUI/src/com/android/systemui/unfold/SysUIUnfoldModule.kt b/packages/SystemUI/src/com/android/systemui/unfold/SysUIUnfoldModule.kt
index 139ac7e..a27989d 100644
--- a/packages/SystemUI/src/com/android/systemui/unfold/SysUIUnfoldModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/unfold/SysUIUnfoldModule.kt
@@ -36,6 +36,7 @@
import dagger.multibindings.IntoSet
import java.util.Optional
import javax.inject.Named
+import javax.inject.Qualifier
import javax.inject.Scope
@Scope @MustBeDocumented @Retention(AnnotationRetention.RUNTIME) annotation class SysUIUnfoldScope
@@ -54,8 +55,17 @@
@Module(subcomponents = [SysUIUnfoldComponent::class])
class SysUIUnfoldModule {
+ /**
+ * Qualifier for dependencies bound in [com.android.systemui.unfold.SysUIUnfoldModule]
+ */
+ @Qualifier
+ @MustBeDocumented
+ @Retention(AnnotationRetention.RUNTIME)
+ annotation class BoundFromSysUiUnfoldModule
+
@Provides
@SysUISingleton
+ @BoundFromSysUiUnfoldModule
fun provideSysUIUnfoldComponent(
provider: Optional<UnfoldTransitionProgressProvider>,
rotationProvider: Optional<NaturalRotationUnfoldProgressProvider>,
diff --git a/packages/SystemUI/src/com/android/systemui/util/kotlin/MapUtils.kt b/packages/SystemUI/src/com/android/systemui/util/kotlin/MapUtils.kt
index 41cd95b..8d202ac 100644
--- a/packages/SystemUI/src/com/android/systemui/util/kotlin/MapUtils.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/kotlin/MapUtils.kt
@@ -30,3 +30,6 @@
}
return destination
}
+
+/** Returns a map with all entries containing `null` values removed. */
+fun <K, V> Map<K, V?>.filterValuesNotNull(): Map<K, V> = mapValuesNotNull { it.value }
diff --git a/packages/SystemUI/src/com/android/systemui/util/kotlin/Utils.kt b/packages/SystemUI/src/com/android/systemui/util/kotlin/Utils.kt
index 405b57a..d9a2e95 100644
--- a/packages/SystemUI/src/com/android/systemui/util/kotlin/Utils.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/kotlin/Utils.kt
@@ -19,19 +19,24 @@
import android.content.Context
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.filter
+import kotlinx.coroutines.flow.map
class Utils {
companion object {
fun <A, B, C> toTriple(a: A, bc: Pair<B, C>) = Triple(a, bc.first, bc.second)
+
fun <A, B, C> toTriple(ab: Pair<A, B>, c: C) = Triple(ab.first, ab.second, c)
fun <A, B, C, D> toQuad(a: A, b: B, c: C, d: D) = Quad(a, b, c, d)
+
fun <A, B, C, D> toQuad(a: A, bcd: Triple<B, C, D>) =
Quad(a, bcd.first, bcd.second, bcd.third)
fun <A, B, C, D> toQuad(abc: Triple<A, B, C>, d: D) =
Quad(abc.first, abc.second, abc.third, d)
fun <A, B, C, D, E> toQuint(a: A, b: B, c: C, d: D, e: E) = Quint(a, b, c, d, e)
+
fun <A, B, C, D, E> toQuint(a: A, bcde: Quad<B, C, D, E>) =
Quint(a, bcde.first, bcde.second, bcde.third, bcde.fourth)
@@ -50,6 +55,14 @@
)
/**
+ * Samples the provided flow, performs a filter on the sampled value, then returns the
+ * original value.
+ */
+ fun <A, B> Flow<A>.sampleFilter(b: Flow<B>, predicate: (B) -> Boolean): Flow<A> {
+ return this.sample(b, ::Pair).filter { (_, b) -> predicate(b) }.map { (a, _) -> a }
+ }
+
+ /**
* Samples the provided flows, emitting a tuple of the original flow's value as well as each
* of the combined flows' values.
*
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index e613216..f457470 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -136,6 +136,7 @@
import com.android.systemui.util.RoundedCornerProgressDrawable;
import com.android.systemui.util.settings.SecureSettings;
import com.android.systemui.volume.domain.interactor.VolumePanelNavigationInteractor;
+import com.android.systemui.volume.panel.shared.flag.VolumePanelFlag;
import com.android.systemui.volume.ui.binder.VolumeDialogMenuIconBinder;
import com.android.systemui.volume.ui.navigation.VolumeNavigator;
@@ -313,6 +314,7 @@
private final VibratorHelper mVibratorHelper;
private final com.android.systemui.util.time.SystemClock mSystemClock;
private final VolumeDialogMenuIconBinder mVolumeDialogMenuIconBinder;
+ private final VolumePanelFlag mVolumePanelFlag;
public VolumeDialogImpl(
Context context,
@@ -328,6 +330,7 @@
CsdWarningDialog.Factory csdWarningDialogFactory,
DevicePostureController devicePostureController,
Looper looper,
+ VolumePanelFlag volumePanelFlag,
DumpManager dumpManager,
Lazy<SecureSettings> secureSettings,
VibratorHelper vibratorHelper,
@@ -366,6 +369,7 @@
mSecureSettings = secureSettings;
mVolumeDialogMenuIconBinder = volumeDialogMenuIconBinder;
mDialogTimeoutMillis = DIALOG_TIMEOUT_MILLIS;
+ mVolumePanelFlag = volumePanelFlag;
dumpManager.registerDumpable("VolumeDialogImpl", this);
@@ -1364,6 +1368,9 @@
}
private void updateODICaptionsH(boolean isServiceComponentEnabled, boolean fromTooltip) {
+ // don't show captions view when the new volume panel is enabled.
+ isServiceComponentEnabled =
+ isServiceComponentEnabled && !mVolumePanelFlag.canUseNewVolumePanel();
if (mODICaptionsView != null) {
mODICaptionsView.setVisibility(isServiceComponentEnabled ? VISIBLE : GONE);
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dagger/VolumeModule.java b/packages/SystemUI/src/com/android/systemui/volume/dagger/VolumeModule.java
index fd68bfb..f8ddc42 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dagger/VolumeModule.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/dagger/VolumeModule.java
@@ -44,6 +44,7 @@
import com.android.systemui.volume.domain.interactor.VolumePanelNavigationInteractor;
import com.android.systemui.volume.panel.dagger.VolumePanelComponent;
import com.android.systemui.volume.panel.dagger.factory.VolumePanelComponentFactory;
+import com.android.systemui.volume.panel.shared.flag.VolumePanelFlag;
import com.android.systemui.volume.ui.binder.VolumeDialogMenuIconBinder;
import com.android.systemui.volume.ui.navigation.VolumeNavigator;
@@ -112,6 +113,7 @@
VolumeNavigator volumeNavigator,
CsdWarningDialog.Factory csdFactory,
DevicePostureController devicePostureController,
+ VolumePanelFlag volumePanelFlag,
DumpManager dumpManager,
Lazy<SecureSettings> secureSettings,
VibratorHelper vibratorHelper,
@@ -131,6 +133,7 @@
csdFactory,
devicePostureController,
Looper.getMainLooper(),
+ volumePanelFlag,
dumpManager,
secureSettings,
vibratorHelper,
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/spatial/ui/viewmodel/SpatialAudioViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/spatial/ui/viewmodel/SpatialAudioViewModel.kt
index 6c6a1cc..324579d 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/spatial/ui/viewmodel/SpatialAudioViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/spatial/ui/viewmodel/SpatialAudioViewModel.kt
@@ -57,7 +57,7 @@
.toViewModel(
isChecked = isEnabled is SpatialAudioEnabledModel.SpatialAudioEnabled,
isHeadTrackingAvailable =
- isAvailable is SpatialAudioAvailabilityModel.SpatialAudio,
+ isAvailable is SpatialAudioAvailabilityModel.HeadTracking,
)
.copy(label = context.getString(R.string.volume_panel_spatial_audio_title))
}
@@ -69,7 +69,7 @@
// head tracking availability means there are three possible states for the spatial
// audio: disabled, enabled regular, enabled with head tracking.
// Show popup in this case instead of a togglealbe button.
- it is SpatialAudioAvailabilityModel.SpatialAudio
+ it is SpatialAudioAvailabilityModel.HeadTracking
}
.stateIn(scope, SharingStarted.Eagerly, false)
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
index 5702a8c..69a6f2a 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
@@ -348,7 +348,8 @@
fun listenForTransitionToAodFromGone_updatesClockDozeAmountToOne() =
runBlocking(IMMEDIATE) {
val transitionStep = MutableStateFlow(TransitionStep())
- whenever(keyguardTransitionInteractor.transitionStepsToState(AOD))
+ whenever(keyguardTransitionInteractor
+ .transition(Edge.create(to = AOD)))
.thenReturn(transitionStep)
val job = underTest.listenForAnyStateToAodTransition(this)
@@ -369,7 +370,8 @@
fun listenForTransitionToLSFromOccluded_updatesClockDozeAmountToZero() =
runBlocking(IMMEDIATE) {
val transitionStep = MutableStateFlow(TransitionStep())
- whenever(keyguardTransitionInteractor.transitionStepsToState(LOCKSCREEN))
+ whenever(keyguardTransitionInteractor
+ .transition(Edge.create(to = LOCKSCREEN)))
.thenReturn(transitionStep)
val job = underTest.listenForAnyStateToLockscreenTransition(this)
@@ -390,7 +392,8 @@
fun listenForTransitionToAodFromLockscreen_neverUpdatesClockDozeAmount() =
runBlocking(IMMEDIATE) {
val transitionStep = MutableStateFlow(TransitionStep())
- whenever(keyguardTransitionInteractor.transitionStepsToState(AOD))
+ whenever(keyguardTransitionInteractor
+ .transition(Edge.create(to = AOD)))
.thenReturn(transitionStep)
val job = underTest.listenForAnyStateToAodTransition(this)
@@ -411,7 +414,8 @@
fun listenForAnyStateToLockscreenTransition_neverUpdatesClockDozeAmount() =
runBlocking(IMMEDIATE) {
val transitionStep = MutableStateFlow(TransitionStep())
- whenever(keyguardTransitionInteractor.transitionStepsToState(LOCKSCREEN))
+ whenever(keyguardTransitionInteractor
+ .transition(Edge.create(to = LOCKSCREEN)))
.thenReturn(transitionStep)
val job = underTest.listenForAnyStateToLockscreenTransition(this)
@@ -432,7 +436,8 @@
fun listenForAnyStateToDozingTransition_UpdatesClockDozeAmountToOne() =
runBlocking(IMMEDIATE) {
val transitionStep = MutableStateFlow(TransitionStep())
- whenever(keyguardTransitionInteractor.transitionStepsToState(DOZING))
+ whenever(keyguardTransitionInteractor
+ .transition(Edge.create(to = DOZING)))
.thenReturn(transitionStep)
val job = underTest.listenForAnyStateToDozingTransition(this)
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/LegacyLockIconViewControllerWithCoroutinesTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/LegacyLockIconViewControllerWithCoroutinesTest.kt
index 25a87b8..9580139 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/LegacyLockIconViewControllerWithCoroutinesTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/LegacyLockIconViewControllerWithCoroutinesTest.kt
@@ -22,10 +22,6 @@
import com.android.keyguard.LockIconView.ICON_LOCK
import com.android.systemui.doze.util.getBurnInOffset
import com.android.systemui.flags.Flags.LOCKSCREEN_WALLPAPER_DREAM_ENABLED
-import com.android.systemui.keyguard.shared.model.KeyguardState.AOD
-import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN
-import com.android.systemui.keyguard.shared.model.TransitionState.FINISHED
-import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.statusbar.StatusBarState
import com.android.systemui.util.mockito.whenever
import kotlinx.coroutines.Dispatchers
@@ -104,7 +100,7 @@
// WHEN dozing updates
mUnderTest.mIsDozingCallback.accept(true)
- mUnderTest.mDozeTransitionCallback.accept(TransitionStep(LOCKSCREEN, AOD, 1f, FINISHED))
+ mUnderTest.mDozeTransitionCallback.accept(1f)
// THEN the view's translation is updated to use the AoD burn-in offsets
verify(mLockIconView).setTranslationY(burnInOffset.toFloat())
@@ -113,7 +109,7 @@
// WHEN the device is no longer dozing
mUnderTest.mIsDozingCallback.accept(false)
- mUnderTest.mDozeTransitionCallback.accept(TransitionStep(AOD, LOCKSCREEN, 0f, FINISHED))
+ mUnderTest.mDozeTransitionCallback.accept(0f)
// THEN the view is updated to NO translation (no burn-in offsets anymore)
verify(mLockIconView).setTranslationY(0f)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/AccessibilityLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/accessibility/AccessibilityLoggerTest.kt
index deacac3..1ce21e77 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/AccessibilityLoggerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/AccessibilityLoggerTest.kt
@@ -16,7 +16,7 @@
package com.android.systemui.accessibility
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.internal.logging.UiEventLogger
import com.android.systemui.SysuiTestCase
@@ -34,7 +34,7 @@
import org.mockito.junit.MockitoJUnit
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class AccessibilityLoggerTest : SysuiTestCase() {
@JvmField @Rule val mockito = MockitoJUnit.rule()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/DisplayIdIndexSupplierTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/DisplayIdIndexSupplierTest.java
index 9cb4fb3..cb8cfc2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/DisplayIdIndexSupplierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/DisplayIdIndexSupplierTest.java
@@ -20,10 +20,10 @@
import static org.junit.Assert.assertNotNull;
import android.hardware.display.DisplayManager;
-import android.testing.AndroidTestingRunner;
import android.view.Display;
import androidx.annotation.NonNull;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -33,7 +33,7 @@
import org.junit.runner.RunWith;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
public class DisplayIdIndexSupplierTest extends SysuiTestCase {
private DisplayIdIndexSupplier<Object> mDisplayIdIndexSupplier;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/FullscreenMagnificationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/FullscreenMagnificationControllerTest.java
index 5bc9aa4..cbd535b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/FullscreenMagnificationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/FullscreenMagnificationControllerTest.java
@@ -21,8 +21,10 @@
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
-import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -34,8 +36,12 @@
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.graphics.Rect;
+import android.os.RemoteException;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import android.view.Display;
+import android.view.IRotationWatcher;
+import android.view.IWindowManager;
import android.view.SurfaceControl;
import android.view.SurfaceControlViewHost;
import android.view.View;
@@ -55,6 +61,8 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -73,9 +81,12 @@
private ValueAnimator mShowHideBorderAnimator;
private SurfaceControl.Transaction mTransaction;
private TestableWindowManager mWindowManager;
+ @Mock
+ private IWindowManager mIWindowManager;
@Before
public void setUp() {
+ MockitoAnnotations.initMocks(this);
getInstrumentation().runOnMainSync(() -> mSurfaceControlViewHost =
spy(new SurfaceControlViewHost(mContext, mContext.getDisplay(),
new InputTransferToken(), "FullscreenMagnification")));
@@ -88,9 +99,11 @@
mShowHideBorderAnimator = spy(newNullTargetObjectAnimator());
mFullscreenMagnificationController = new FullscreenMagnificationController(
mContext,
+ mContext.getMainThreadHandler(),
mContext.getMainExecutor(),
mContext.getSystemService(AccessibilityManager.class),
mContext.getSystemService(WindowManager.class),
+ mIWindowManager,
scvhSupplier,
mTransaction,
mShowHideBorderAnimator);
@@ -104,7 +117,8 @@
}
@Test
- public void enableFullscreenMagnification_visibleBorder() throws InterruptedException {
+ public void enableFullscreenMagnification_visibleBorder()
+ throws InterruptedException, RemoteException {
CountDownLatch transactionCommittedLatch = new CountDownLatch(1);
CountDownLatch animationEndLatch = new CountDownLatch(1);
mTransaction.addTransactionCommittedListener(
@@ -119,17 +133,21 @@
//Enable fullscreen magnification
mFullscreenMagnificationController
.onFullscreenMagnificationActivationChanged(true));
- assertTrue("Failed to wait for transaction committed",
- transactionCommittedLatch.await(WAIT_TIMEOUT_S, TimeUnit.SECONDS));
- assertTrue("Failed to wait for animation to be finished",
- animationEndLatch.await(ANIMATION_TIMEOUT_MS, TimeUnit.MILLISECONDS));
+ assertWithMessage("Failed to wait for transaction committed")
+ .that(transactionCommittedLatch.await(WAIT_TIMEOUT_S, TimeUnit.SECONDS))
+ .isTrue();
+ assertWithMessage("Failed to wait for animation to be finished")
+ .that(animationEndLatch.await(ANIMATION_TIMEOUT_MS, TimeUnit.MILLISECONDS))
+ .isTrue();
verify(mShowHideBorderAnimator).start();
+ verify(mIWindowManager)
+ .watchRotation(any(IRotationWatcher.class), eq(Display.DEFAULT_DISPLAY));
assertThat(mSurfaceControlViewHost.getView().isVisibleToUser()).isTrue();
}
@Test
public void disableFullscreenMagnification_reverseAnimationAndReleaseScvh()
- throws InterruptedException {
+ throws InterruptedException, RemoteException {
CountDownLatch transactionCommittedLatch = new CountDownLatch(1);
CountDownLatch enableAnimationEndLatch = new CountDownLatch(1);
CountDownLatch disableAnimationEndLatch = new CountDownLatch(1);
@@ -149,11 +167,12 @@
//Enable fullscreen magnification
mFullscreenMagnificationController
.onFullscreenMagnificationActivationChanged(true));
- assertTrue("Failed to wait for transaction committed",
- transactionCommittedLatch.await(WAIT_TIMEOUT_S, TimeUnit.SECONDS));
- assertTrue("Failed to wait for enabling animation to be finished",
- enableAnimationEndLatch.await(
- ANIMATION_TIMEOUT_MS, TimeUnit.MILLISECONDS));
+ assertWithMessage("Failed to wait for transaction committed")
+ .that(transactionCommittedLatch.await(WAIT_TIMEOUT_S, TimeUnit.SECONDS))
+ .isTrue();
+ assertWithMessage("Failed to wait for enabling animation to be finished")
+ .that(enableAnimationEndLatch.await(ANIMATION_TIMEOUT_MS, TimeUnit.MILLISECONDS))
+ .isTrue();
verify(mShowHideBorderAnimator).start();
getInstrumentation().runOnMainSync(() ->
@@ -161,11 +180,12 @@
mFullscreenMagnificationController
.onFullscreenMagnificationActivationChanged(false));
- assertTrue("Failed to wait for disabling animation to be finished",
- disableAnimationEndLatch.await(
- ANIMATION_TIMEOUT_MS, TimeUnit.MILLISECONDS));
+ assertWithMessage("Failed to wait for disabling animation to be finished")
+ .that(disableAnimationEndLatch.await(ANIMATION_TIMEOUT_MS, TimeUnit.MILLISECONDS))
+ .isTrue();
verify(mShowHideBorderAnimator).reverse();
verify(mSurfaceControlViewHost).release();
+ verify(mIWindowManager).removeRotationWatcher(any(IRotationWatcher.class));
}
@Test
@@ -188,10 +208,12 @@
() -> mFullscreenMagnificationController
.onFullscreenMagnificationActivationChanged(true));
- assertTrue("Failed to wait for transaction committed",
- transactionCommittedLatch.await(WAIT_TIMEOUT_S, TimeUnit.SECONDS));
- assertTrue("Failed to wait for animation to be finished",
- animationEndLatch.await(ANIMATION_TIMEOUT_MS, TimeUnit.MILLISECONDS));
+ assertWithMessage("Failed to wait for transaction committed")
+ .that(transactionCommittedLatch.await(WAIT_TIMEOUT_S, TimeUnit.SECONDS))
+ .isTrue();
+ assertWithMessage("Failed to wait for animation to be finished")
+ .that(animationEndLatch.await(ANIMATION_TIMEOUT_MS, TimeUnit.MILLISECONDS))
+ .isTrue();
verify(mShowHideBorderAnimator).reverse();
}
@@ -212,10 +234,12 @@
//Enable fullscreen magnification
mFullscreenMagnificationController
.onFullscreenMagnificationActivationChanged(true));
- assertTrue("Failed to wait for transaction committed",
- transactionCommittedLatch.await(WAIT_TIMEOUT_S, TimeUnit.SECONDS));
- assertTrue("Failed to wait for animation to be finished",
- animationEndLatch.await(ANIMATION_TIMEOUT_MS, TimeUnit.MILLISECONDS));
+ assertWithMessage("Failed to wait for transaction committed")
+ .that(transactionCommittedLatch.await(WAIT_TIMEOUT_S, TimeUnit.SECONDS))
+ .isTrue();
+ assertWithMessage("Failed to wait for animation to be finished")
+ .that(animationEndLatch.await(ANIMATION_TIMEOUT_MS, TimeUnit.MILLISECONDS))
+ .isTrue();
final Rect testWindowBounds = new Rect(
mWindowManager.getCurrentWindowMetrics().getBounds());
testWindowBounds.set(testWindowBounds.left, testWindowBounds.top,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/IMagnificationConnectionTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/IMagnificationConnectionTest.java
index 3164f8e..361a945 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/IMagnificationConnectionTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/IMagnificationConnectionTest.java
@@ -37,14 +37,15 @@
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.provider.Settings;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.Display;
+import android.view.IWindowManager;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.IMagnificationConnection;
import android.view.accessibility.IMagnificationConnectionCallback;
import android.view.accessibility.IRemoteMagnificationAnimationCallback;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.Flags;
@@ -67,7 +68,7 @@
* {@link Magnification}
*/
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
public class IMagnificationConnectionTest extends SysuiTestCase {
@@ -99,6 +100,8 @@
private SecureSettings mSecureSettings;
@Mock
private AccessibilityLogger mA11yLogger;
+ @Mock
+ private IWindowManager mIWindowManager;
private IMagnificationConnection mIMagnificationConnection;
private Magnification mMagnification;
@@ -117,9 +120,10 @@
mTestableLooper = TestableLooper.get(this);
assertNotNull(mTestableLooper);
mMagnification = new Magnification(getContext(),
- mTestableLooper.getLooper(), getContext().getMainExecutor(), mCommandQueue,
+ mTestableLooper.getLooper(), mContext.getMainExecutor(), mCommandQueue,
mModeSwitchesController, mSysUiState, mOverviewProxyService, mSecureSettings,
- mDisplayTracker, getContext().getSystemService(DisplayManager.class), mA11yLogger);
+ mDisplayTracker, getContext().getSystemService(DisplayManager.class),
+ mA11yLogger, mIWindowManager);
mMagnification.mWindowMagnificationControllerSupplier =
new FakeWindowMagnificationControllerSupplier(
mContext.getSystemService(DisplayManager.class));
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 ad02179..7b06dd6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationGestureDetectorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationGestureDetectorTest.java
@@ -26,11 +26,11 @@
import android.os.Handler;
import android.os.SystemClock;
-import android.testing.AndroidTestingRunner;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -45,7 +45,7 @@
import org.mockito.MockitoAnnotations;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
public class MagnificationGestureDetectorTest extends SysuiTestCase {
private static final float ACTION_DOWN_X = 100;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java
index 1a88545..5be1180 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java
@@ -58,7 +58,6 @@
import android.graphics.Rect;
import android.os.Handler;
import android.os.SystemClock;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.Choreographer;
import android.view.MotionEvent;
@@ -71,6 +70,7 @@
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.ImageView;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
@@ -90,7 +90,7 @@
import java.util.List;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
public class MagnificationModeSwitchTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationSettingsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationSettingsControllerTest.java
index 9eead6a..d0f8e78 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationSettingsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationSettingsControllerTest.java
@@ -22,9 +22,9 @@
import static org.mockito.Mockito.verify;
import android.content.pm.ActivityInfo;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
@@ -40,7 +40,7 @@
import org.mockito.MockitoAnnotations;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
/** Tests the MagnificationSettingsController. */
@TestableLooper.RunWithLooper(setAsMainLooper = true)
public class MagnificationSettingsControllerTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationTest.java
index bbdd805..17b7e21 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationTest.java
@@ -40,13 +40,14 @@
import android.graphics.Rect;
import android.hardware.display.DisplayManager;
import android.os.RemoteException;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.Display;
+import android.view.IWindowManager;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.IMagnificationConnection;
import android.view.accessibility.IMagnificationConnectionCallback;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -64,7 +65,7 @@
import org.mockito.MockitoAnnotations;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper
public class MagnificationTest extends SysuiTestCase {
@@ -93,6 +94,8 @@
private MagnificationSettingsController mMagnificationSettingsController;
@Mock
private AccessibilityLogger mA11yLogger;
+ @Mock
+ private IWindowManager mIWindowManager;
@Before
public void setUp() throws Exception {
@@ -122,10 +125,10 @@
mCommandQueue = new CommandQueue(getContext(), mDisplayTracker);
mMagnification = new Magnification(getContext(),
- getContext().getMainThreadHandler(), getContext().getMainExecutor(),
+ getContext().getMainThreadHandler(), mContext.getMainExecutor(),
mCommandQueue, mModeSwitchesController,
mSysUiState, mOverviewProxyService, mSecureSettings, mDisplayTracker,
- getContext().getSystemService(DisplayManager.class), mA11yLogger);
+ getContext().getSystemService(DisplayManager.class), mA11yLogger, mIWindowManager);
mMagnification.mWindowMagnificationControllerSupplier = new FakeControllerSupplier(
mContext.getSystemService(DisplayManager.class), mWindowMagnificationController);
mMagnification.mMagnificationSettingsSupplier = new FakeSettingsSupplier(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/MirrorWindowControlTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/MirrorWindowControlTest.java
index e81613e..8f9b7c8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/MirrorWindowControlTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/MirrorWindowControlTest.java
@@ -27,12 +27,12 @@
import android.content.Context;
import android.graphics.Point;
-import android.testing.AndroidTestingRunner;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -45,7 +45,7 @@
import org.mockito.MockitoAnnotations;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
public class MirrorWindowControlTest extends SysuiTestCase {
@Mock WindowManager mWindowManager;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/ModeSwitchesControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/ModeSwitchesControllerTest.java
index 3c97423..6e94297 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/ModeSwitchesControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/ModeSwitchesControllerTest.java
@@ -21,11 +21,11 @@
import android.content.pm.ActivityInfo;
import android.hardware.display.DisplayManager;
import android.provider.Settings;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.Display;
import android.view.View;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -39,7 +39,7 @@
import org.mockito.MockitoAnnotations;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
/** Tests the ModeSwitchesController. */
@TestableLooper.RunWithLooper(setAsMainLooper = true)
public class ModeSwitchesControllerTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/SecureSettingsContentObserverTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/SecureSettingsContentObserverTest.java
index 9c601a8..9222fc2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/SecureSettingsContentObserverTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/SecureSettingsContentObserverTest.java
@@ -21,8 +21,8 @@
import android.app.ActivityManager;
import android.content.Context;
import android.provider.Settings;
-import android.testing.AndroidTestingRunner;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -34,7 +34,7 @@
import org.mockito.Mockito;
/** Test for {@link SecureSettingsContentObserver}. */
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@SmallTest
public class SecureSettingsContentObserverTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/SystemActionsTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/SystemActionsTest.java
index c674294..f46b2f9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/SystemActionsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/SystemActionsTest.java
@@ -28,10 +28,10 @@
import android.os.RemoteException;
import android.telecom.TelecomManager;
import android.telephony.TelephonyManager;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.KeyEvent;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -55,7 +55,7 @@
@TestableLooper.RunWithLooper
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
public class SystemActionsTest extends SysuiTestCase {
@Mock
private UserTracker mUserTracker;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
index cb42078..f57003e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
@@ -72,7 +72,6 @@
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.provider.Settings;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.testing.TestableResources;
import android.text.TextUtils;
@@ -90,6 +89,7 @@
import android.view.accessibility.IRemoteMagnificationAnimationCallback;
import androidx.test.InstrumentationRegistry;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.LargeTest;
import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
@@ -125,7 +125,7 @@
@LargeTest
@TestableLooper.RunWithLooper
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@RequiresFlagsDisabled(Flags.FLAG_CREATE_WINDOWLESS_WINDOW_MAGNIFIER)
public class WindowMagnificationControllerTest extends SysuiTestCase {
@@ -1511,4 +1511,4 @@
});
}
}
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerWindowlessMagnifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerWindowlessMagnifierTest.java
index 01e4d58..e272682 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerWindowlessMagnifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerWindowlessMagnifierTest.java
@@ -71,7 +71,6 @@
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.provider.Settings;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.testing.TestableResources;
import android.text.TextUtils;
@@ -94,6 +93,7 @@
import android.window.InputTransferToken;
import androidx.test.InstrumentationRegistry;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.LargeTest;
import com.android.systemui.Flags;
@@ -129,7 +129,7 @@
@LargeTest
@TestableLooper.RunWithLooper
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@RequiresFlagsEnabled(Flags.FLAG_CREATE_WINDOWLESS_WINDOW_MAGNIFIER)
public class WindowMagnificationControllerWindowlessMagnifierTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationFrameSizePrefsTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationFrameSizePrefsTest.java
index 93c0eea..ad9053a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationFrameSizePrefsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationFrameSizePrefsTest.java
@@ -23,10 +23,10 @@
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.util.Size;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -37,7 +37,7 @@
import org.junit.runner.RunWith;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper
public class WindowMagnificationFrameSizePrefsTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationSettingsTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationSettingsTest.java
index 138fed2..003f7e4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationSettingsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationSettingsTest.java
@@ -47,7 +47,6 @@
import android.graphics.Rect;
import android.os.UserHandle;
import android.provider.Settings;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.View;
import android.view.ViewGroup;
@@ -59,6 +58,7 @@
import android.widget.LinearLayout;
import androidx.test.InstrumentationRegistry;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
@@ -77,7 +77,7 @@
import org.mockito.MockitoAnnotations;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper
public class WindowMagnificationSettingsTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/data/repository/AccessibilityRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/accessibility/data/repository/AccessibilityRepositoryTest.kt
index aff52f5..c4a92bf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/data/repository/AccessibilityRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/data/repository/AccessibilityRepositoryTest.kt
@@ -18,8 +18,8 @@
package com.android.systemui.accessibility.data.repository
-import android.testing.AndroidTestingRunner
import android.view.accessibility.AccessibilityManager
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
@@ -37,7 +37,7 @@
import org.mockito.junit.MockitoJUnit
import org.mockito.junit.MockitoRule
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
class AccessibilityRepositoryTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuControllerTest.java
index 095c945..b71739a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuControllerTest.java
@@ -30,11 +30,11 @@
import android.hardware.display.DisplayManager;
import android.os.UserHandle;
import android.provider.Settings;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityManager;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.keyguard.KeyguardUpdateMonitor;
@@ -59,7 +59,7 @@
import org.mockito.junit.MockitoRule;
/** Test for {@link AccessibilityFloatingMenuController}. */
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
@SmallTest
public class AccessibilityFloatingMenuControllerTest 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 630db62..b08f97a 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
@@ -21,10 +21,10 @@
import static org.mockito.Mockito.when;
import android.graphics.drawable.Drawable;
-import android.testing.AndroidTestingRunner;
import android.view.LayoutInflater;
import android.view.View;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.internal.accessibility.dialog.AccessibilityTarget;
@@ -43,7 +43,7 @@
/** Tests for {@link AccessibilityTargetAdapter}. */
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
public class AccessibilityTargetAdapterTest extends SysuiTestCase {
@Mock
private AccessibilityTarget mAccessibilityTarget;
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 4b87588..5b2afe7 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
@@ -20,10 +20,10 @@
import static org.mockito.Mockito.mock;
-import android.testing.AndroidTestingRunner;
import android.text.SpannableStringBuilder;
import android.view.View;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -37,7 +37,7 @@
/** Tests for {@link AnnotationLinkSpan}. */
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
public class AnnotationLinkSpanTest extends SysuiTestCase {
private AnnotationLinkSpan.LinkInfo mLinkInfo;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/DragToInteractAnimationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/DragToInteractAnimationControllerTest.java
index abc95bc..19b2700 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/DragToInteractAnimationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/DragToInteractAnimationControllerTest.java
@@ -22,11 +22,11 @@
import android.annotation.NonNull;
import android.platform.test.annotations.DisableFlags;
import android.platform.test.annotations.EnableFlags;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityManager;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.Flags;
@@ -46,7 +46,7 @@
/** Tests for {@link DragToInteractAnimationController}. */
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper
public class DragToInteractAnimationControllerTest extends SysuiTestCase {
private DragToInteractAnimationController mDragToInteractAnimationController;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuEduTooltipViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuEduTooltipViewTest.java
index 34a2e87..b597737 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuEduTooltipViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuEduTooltipViewTest.java
@@ -19,11 +19,11 @@
import static com.google.common.truth.Truth.assertThat;
import android.content.res.Resources;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.WindowManager;
import android.widget.TextView;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -35,7 +35,7 @@
/** Tests for {@link MenuEduTooltipView}. */
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper
public class MenuEduTooltipViewTest extends SysuiTestCase {
private MenuViewAppearance mMenuViewAppearance;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuInfoRepositoryTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuInfoRepositoryTest.java
index 1faa8ac..24f3a29 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuInfoRepositoryTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuInfoRepositoryTest.java
@@ -25,9 +25,9 @@
import android.content.Context;
import android.content.res.Configuration;
-import android.testing.AndroidTestingRunner;
import android.view.accessibility.AccessibilityManager;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -47,7 +47,7 @@
import java.util.Locale;
/** Tests for {@link MenuInfoRepository}. */
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@SmallTest
public class MenuInfoRepositoryTest extends SysuiTestCase {
@Rule
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuItemAccessibilityDelegateTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuItemAccessibilityDelegateTest.java
index 1f7d033..c5509ac 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuItemAccessibilityDelegateTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuItemAccessibilityDelegateTest.java
@@ -30,7 +30,6 @@
import android.graphics.Rect;
import android.platform.test.annotations.DisableFlags;
import android.platform.test.annotations.EnableFlags;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityManager;
@@ -39,6 +38,7 @@
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.RecyclerViewAccessibilityDelegate;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.Flags;
@@ -60,7 +60,7 @@
/** Tests for {@link MenuItemAccessibilityDelegate}. */
@SmallTest
@TestableLooper.RunWithLooper
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
public class MenuItemAccessibilityDelegateTest extends SysuiTestCase {
@Rule
public MockitoRule mockito = MockitoJUnit.rule();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuListViewTouchHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuListViewTouchHandlerTest.java
index 9e8c6b3..4373c88 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuListViewTouchHandlerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuListViewTouchHandlerTest.java
@@ -30,7 +30,6 @@
import android.platform.test.annotations.DisableFlags;
import android.platform.test.annotations.EnableFlags;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.MotionEvent;
import android.view.WindowManager;
@@ -38,6 +37,7 @@
import androidx.dynamicanimation.animation.DynamicAnimation;
import androidx.recyclerview.widget.RecyclerView;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.internal.accessibility.dialog.AccessibilityTarget;
@@ -62,7 +62,7 @@
import java.util.List;
/** Tests for {@link MenuListViewTouchHandler}. */
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
@SmallTest
public class MenuListViewTouchHandlerTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuNotificationFactoryTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuNotificationFactoryTest.java
index 9dd337e..2746fef 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuNotificationFactoryTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuNotificationFactoryTest.java
@@ -19,8 +19,8 @@
import static com.google.common.truth.Truth.assertThat;
import android.app.Notification;
-import android.testing.AndroidTestingRunner;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -29,7 +29,7 @@
import org.junit.Test;
import org.junit.runner.RunWith;
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@SmallTest
public class MenuNotificationFactoryTest extends SysuiTestCase {
private MenuNotificationFactory mMenuNotificationFactory;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerControllerTest.java
index 31824ec..bd1a7f0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerControllerTest.java
@@ -27,7 +27,6 @@
import android.content.Context;
import android.graphics.Insets;
import android.graphics.Rect;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.View;
import android.view.ViewGroup;
@@ -36,6 +35,7 @@
import android.view.WindowMetrics;
import android.view.accessibility.AccessibilityManager;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -50,7 +50,7 @@
import org.mockito.junit.MockitoRule;
/** Tests for {@link MenuViewLayerController}. */
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
@SmallTest
public class MenuViewLayerControllerTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java
index 05d7560..38095c8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java
@@ -61,7 +61,6 @@
import android.platform.test.annotations.DisableFlags;
import android.platform.test.annotations.EnableFlags;
import android.provider.Settings;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.util.ArraySet;
import android.view.View;
@@ -72,6 +71,7 @@
import androidx.dynamicanimation.animation.DynamicAnimation;
import androidx.dynamicanimation.animation.SpringAnimation;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.internal.accessibility.common.ShortcutConstants;
@@ -101,7 +101,7 @@
import java.util.List;
/** Tests for {@link MenuViewLayer}. */
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
@SmallTest
public class MenuViewLayerTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewTest.java
index f6288b6..103449b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewTest.java
@@ -29,11 +29,11 @@
import android.graphics.Rect;
import android.graphics.drawable.GradientDrawable;
import android.platform.test.annotations.EnableFlags;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityManager;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.Flags;
@@ -53,7 +53,7 @@
import org.mockito.junit.MockitoRule;
/** Tests for {@link MenuView}. */
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
@SmallTest
public class MenuViewTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/PositionTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/PositionTest.java
index 05f306b..8fb71fa 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/PositionTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/PositionTest.java
@@ -18,8 +18,8 @@
import static com.google.common.truth.Truth.assertThat;
-import android.testing.AndroidTestingRunner;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -29,7 +29,7 @@
/** Tests for {@link Position}. */
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
public class PositionTest extends SysuiTestCase {
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/RadiiAnimatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/RadiiAnimatorTest.java
index d77a80a..f67e8d0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/RadiiAnimatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/RadiiAnimatorTest.java
@@ -20,8 +20,8 @@
import android.os.Handler;
import android.os.Looper;
-import android.testing.AndroidTestingRunner;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -35,7 +35,7 @@
/** Tests for {@link RadiiAnimator}. */
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
public class RadiiAnimatorTest extends SysuiTestCase {
float[] mResultRadii = new float[RadiiAnimator.RADII_COUNT];
final AtomicBoolean mAnimationStarted = new AtomicBoolean(false);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/fontscaling/FontScalingDialogDelegateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/accessibility/fontscaling/FontScalingDialogDelegateTest.kt
index e371b39..0bd00fb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/fontscaling/FontScalingDialogDelegateTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/fontscaling/FontScalingDialogDelegateTest.kt
@@ -18,12 +18,12 @@
import android.content.res.Configuration
import android.os.Handler
import android.provider.Settings
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.view.LayoutInflater
import android.view.ViewGroup
import android.widget.Button
import android.widget.SeekBar
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.animation.DialogTransitionAnimator
@@ -58,7 +58,7 @@
/** Tests for [FontScalingDialogDelegate]. */
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
class FontScalingDialogDelegateTest : SysuiTestCase() {
private lateinit var fontScalingDialogDelegate: FontScalingDialogDelegate
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegateTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegateTest.java
index 0db0de2..8f7dc7cf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegateTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegateTest.java
@@ -39,11 +39,11 @@
import android.os.Handler;
import android.platform.test.annotations.EnableFlags;
import android.provider.Settings;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.View;
import android.widget.LinearLayout;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.settingslib.bluetooth.BluetoothEventManager;
@@ -78,7 +78,7 @@
import java.util.List;
/** Tests for {@link HearingDevicesDialogDelegate}. */
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
@SmallTest
public class HearingDevicesDialogDelegateTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogManagerTest.java
index cb9c26c..09aa2868 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogManagerTest.java
@@ -21,9 +21,10 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import android.testing.AndroidTestingRunner;
+import android.bluetooth.BluetoothDevice;
import android.testing.TestableLooper;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -42,7 +43,7 @@
import org.mockito.junit.MockitoRule;
/** Tests for {@link HearingDevicesDialogManager}. */
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
@SmallTest
public class HearingDevicesDialogManagerTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesListAdapterTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesListAdapterTest.java
index d16db65..9359adf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesListAdapterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesListAdapterTest.java
@@ -20,9 +20,9 @@
import static org.mockito.Mockito.when;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
@@ -41,7 +41,7 @@
import java.util.List;
/** Tests for {@link HearingDevicesListAdapter}. */
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
@SmallTest
public class HearingDevicesListAdapterTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesToolItemParserTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesToolItemParserTest.java
index 7172923..17ce1dd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesToolItemParserTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesToolItemParserTest.java
@@ -28,9 +28,9 @@
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -48,7 +48,7 @@
/**
* Tests for {@link HearingDevicesToolItemParser}.
*/
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
@SmallTest
public class HearingDevicesToolItemParserTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/ambient/touch/InputSessionTest.java b/packages/SystemUI/tests/src/com/android/systemui/ambient/touch/InputSessionTest.java
index 2f4999b..8fca557 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/ambient/touch/InputSessionTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/ambient/touch/InputSessionTest.java
@@ -24,13 +24,13 @@
import static org.mockito.Mockito.when;
import android.platform.test.annotations.EnableFlags;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.Choreographer;
import android.view.GestureDetector;
import android.view.InputEvent;
import android.view.MotionEvent;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.Flags;
@@ -50,7 +50,7 @@
* A test suite for exercising {@link InputSession}.
*/
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper()
public class InputSessionTest extends SysuiTestCase {
@Mock
diff --git a/packages/SystemUI/tests/src/com/android/systemui/ambient/touch/TouchMonitorTest.java b/packages/SystemUI/tests/src/com/android/systemui/ambient/touch/TouchMonitorTest.java
index 358e8cb..4118c90 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/ambient/touch/TouchMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/ambient/touch/TouchMonitorTest.java
@@ -36,7 +36,6 @@
import android.hardware.display.DisplayManager;
import android.platform.test.annotations.DisableFlags;
import android.platform.test.annotations.EnableFlags;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.GestureDetector;
import android.view.IWindowManager;
@@ -50,6 +49,7 @@
import androidx.lifecycle.LifecycleObserver;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.LifecycleRegistry;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.Flags;
@@ -79,7 +79,7 @@
import java.util.stream.Stream;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
public class TouchMonitorTest extends SysuiTestCase {
private KosmosJavaAdapter mKosmos;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityTransitionAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityTransitionAnimatorTest.kt
index 70a544c..9aaf295 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityTransitionAnimatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityTransitionAnimatorTest.kt
@@ -9,7 +9,6 @@
import android.graphics.Rect
import android.os.Looper
import android.platform.test.flag.junit.SetFlagsRule
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
import android.view.IRemoteAnimationFinishedCallback
import android.view.RemoteAnimationAdapter
@@ -20,6 +19,7 @@
import android.widget.LinearLayout
import android.window.RemoteTransition
import android.window.TransitionFilter
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.shared.Flags
@@ -49,7 +49,7 @@
import org.mockito.junit.MockitoJUnit
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@RunWithLooper
class ActivityTransitionAnimatorTest : SysuiTestCase() {
private val transitionContainer = LinearLayout(mContext)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/AnimatorTestRuleOrderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/AnimatorTestRuleOrderTest.kt
index e3be3822..37f549a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/animation/AnimatorTestRuleOrderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/AnimatorTestRuleOrderTest.kt
@@ -16,9 +16,9 @@
package com.android.systemui.animation
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
import androidx.core.animation.doOnEnd
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.FlakyTest
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
@@ -28,7 +28,7 @@
import org.junit.Test
import org.junit.runner.RunWith
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
@RunWithLooper
@FlakyTest(bugId = 302149604)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/DialogTransitionAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/DialogTransitionAnimatorTest.kt
index e14762cd..a60fb76 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/animation/DialogTransitionAnimatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/DialogTransitionAnimatorTest.kt
@@ -5,7 +5,6 @@
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.os.Bundle
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.testing.ViewUtils
import android.view.View
@@ -14,6 +13,7 @@
import android.view.WindowManager
import android.widget.FrameLayout
import android.widget.LinearLayout
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.internal.jank.Cuj
import com.android.internal.policy.DecorView
@@ -39,7 +39,7 @@
import org.mockito.junit.MockitoRule
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@TestableLooper.RunWithLooper
class DialogTransitionAnimatorTest : SysuiTestCase() {
private val kosmos = testKosmos()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/FontInterpolatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/FontInterpolatorTest.kt
index 5e1a8e1..ec42b7f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/animation/FontInterpolatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/FontInterpolatorTest.kt
@@ -20,14 +20,14 @@
import android.graphics.fonts.Font
import android.graphics.fonts.FontVariationAxis
import android.graphics.text.TextRunShaper
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.google.common.truth.Truth.assertThat
import org.junit.Test
import org.junit.runner.RunWith
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
class FontInterpolatorTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/FontVariationUtilsTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/FontVariationUtilsTest.kt
index 070cad7..b0f81c0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/animation/FontVariationUtilsTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/FontVariationUtilsTest.kt
@@ -1,6 +1,6 @@
package com.android.systemui.animation
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import junit.framework.Assert
@@ -12,7 +12,7 @@
private const val TAG_OPSZ = "opsz"
private const val TAG_ROND = "ROND"
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
class FontVariationUtilsTest : SysuiTestCase() {
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/GhostedViewTransitionAnimatorControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/GhostedViewTransitionAnimatorControllerTest.kt
index 42fcd54..e492c63 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/animation/GhostedViewTransitionAnimatorControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/GhostedViewTransitionAnimatorControllerTest.kt
@@ -17,10 +17,10 @@
package com.android.systemui.animation
import android.os.HandlerThread
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.view.View
import android.widget.FrameLayout
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.internal.jank.InteractionJankMonitor
import com.android.systemui.SysuiTestCase
@@ -31,7 +31,7 @@
import org.junit.runner.RunWith
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@TestableLooper.RunWithLooper
class GhostedViewTransitionAnimatorControllerTest : SysuiTestCase() {
companion object {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/TextAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/TextAnimatorTest.kt
index 263d375..6ba1715 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/animation/TextAnimatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/TextAnimatorTest.kt
@@ -19,10 +19,10 @@
import android.animation.AnimatorListenerAdapter
import android.animation.ValueAnimator
import android.graphics.Typeface
-import android.testing.AndroidTestingRunner
import android.text.Layout
import android.text.StaticLayout
import android.text.TextPaint
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.google.common.truth.Truth.assertThat
@@ -38,7 +38,7 @@
import org.mockito.Mockito.verify
import org.mockito.Mockito.`when`
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
class TextAnimatorTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/TextInterpolatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/TextInterpolatorTest.kt
index f6fcd16..cca5f35 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/animation/TextInterpolatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/TextInterpolatorTest.kt
@@ -22,12 +22,12 @@
import android.graphics.Typeface
import android.graphics.fonts.Font
import android.graphics.fonts.FontFamily
-import android.testing.AndroidTestingRunner
import android.text.Layout
import android.text.StaticLayout
import android.text.TextDirectionHeuristic
import android.text.TextDirectionHeuristics
import android.text.TextPaint
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.google.common.truth.Truth.assertThat
@@ -62,7 +62,7 @@
typeface = Font.Builder(VF_FONT).setFontVariationSettings("'wght' 700").build().toTypeface()
}
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
class TextInterpolatorTest : SysuiTestCase() {
lateinit var typefaceCache: TypefaceVariantCache
@@ -330,4 +330,4 @@
Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888).also { draw(Canvas(it)) }!!
private fun TextInterpolator.toBitmap(width: Int, height: Int) =
- Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888).also { draw(Canvas(it)) }
\ No newline at end of file
+ Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888).also { draw(Canvas(it)) }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/ViewHierarchyAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/ViewHierarchyAnimatorTest.kt
index c2e6db3..a8c3af9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/animation/ViewHierarchyAnimatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/ViewHierarchyAnimatorTest.kt
@@ -1,12 +1,12 @@
package com.android.systemui.animation
import android.animation.ObjectAnimator
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.view.View
import android.view.ViewGroup
import android.widget.LinearLayout
import android.widget.RelativeLayout
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.app.animation.Interpolators
import com.android.systemui.SysuiTestCase
@@ -22,7 +22,7 @@
import org.junit.runner.RunWith
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@TestableLooper.RunWithLooper
class
ViewHierarchyAnimatorTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/back/BackAnimationSpecTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/back/BackAnimationSpecTest.kt
index 0ed84ea..4809d0e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/animation/back/BackAnimationSpecTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/back/BackAnimationSpecTest.kt
@@ -2,6 +2,7 @@
import android.util.DisplayMetrics
import android.window.BackEvent
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.util.dpToPx
@@ -9,12 +10,11 @@
import junit.framework.TestCase.assertEquals
import org.junit.Test
import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
private data class BackInput(val progressX: Float, val progressY: Float, val edge: Int)
@SmallTest
-@RunWith(JUnit4::class)
+@RunWith(AndroidJUnit4::class)
class BackAnimationSpecTest : SysuiTestCase() {
private var displayMetrics =
DisplayMetrics().apply {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/back/BackTransformationTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/back/BackTransformationTest.kt
index 44a5467..d898d1c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/animation/back/BackTransformationTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/back/BackTransformationTest.kt
@@ -1,6 +1,7 @@
package com.android.systemui.animation.back
import android.view.View
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.util.mockito.mock
@@ -8,13 +9,12 @@
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
import org.mockito.Mockito.verify
import org.mockito.Mockito.verifyNoMoreInteractions
import org.mockito.kotlin.whenever
@SmallTest
-@RunWith(JUnit4::class)
+@RunWith(AndroidJUnit4::class)
class BackTransformationTest : SysuiTestCase() {
private val targetView: View = mock()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/back/OnBackAnimationCallbackExtensionTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/back/OnBackAnimationCallbackExtensionTest.kt
index 314abda..9548e29 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/animation/back/OnBackAnimationCallbackExtensionTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/back/OnBackAnimationCallbackExtensionTest.kt
@@ -2,6 +2,7 @@
import android.util.DisplayMetrics
import android.window.BackEvent
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.util.mockito.argumentCaptor
@@ -10,11 +11,10 @@
import com.google.common.truth.Truth.assertThat
import org.junit.Test
import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
import org.mockito.Mockito.verify
@SmallTest
-@RunWith(JUnit4::class)
+@RunWith(AndroidJUnit4::class)
class OnBackAnimationCallbackExtensionTest : SysuiTestCase() {
private val onBackProgress: (BackTransformation) -> Unit = mock()
private val onBackStart: (BackEvent) -> Unit = mock()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java
index 0d464cf..476d6e3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java
@@ -49,9 +49,9 @@
import android.media.AudioRecordingConfiguration;
import android.os.Looper;
import android.os.UserHandle;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.internal.R;
@@ -75,7 +75,7 @@
import java.util.Map;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper
public class AppOpsControllerTest extends SysuiTestCase {
private static final String TEST_PACKAGE_NAME = "test";
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 4d582ab..828d367 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
@@ -21,8 +21,8 @@
import android.content.Context;
import android.content.res.Resources;
-import android.testing.AndroidTestingRunner;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -35,7 +35,7 @@
import org.mockito.MockitoAnnotations;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
public class DisplayUtilsTest extends SysuiTestCase {
@Mock
diff --git a/packages/SystemUI/tests/src/com/android/systemui/battery/BatteryMeterViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/battery/BatteryMeterViewTest.kt
index 3c073d5..2bd0976 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/battery/BatteryMeterViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/battery/BatteryMeterViewTest.kt
@@ -17,9 +17,9 @@
import android.platform.test.annotations.DisableFlags
import android.platform.test.annotations.EnableFlags
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
import android.widget.ImageView
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.settingslib.flags.Flags.FLAG_NEW_STATUS_BAR_ICONS
import com.android.systemui.res.R
@@ -33,7 +33,7 @@
import org.mockito.MockitoAnnotations
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@RunWithLooper
class BatteryMeterViewTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt
index 7c03d78..6dc4b10 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt
@@ -19,9 +19,9 @@
import android.graphics.Point
import android.hardware.biometrics.BiometricSourceType
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
import android.util.DisplayMetrics
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession
import com.android.keyguard.KeyguardUpdateMonitor
@@ -67,7 +67,7 @@
@ExperimentalCoroutinesApi
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class AuthRippleControllerTest : SysuiTestCase() {
private lateinit var staticMockSession: MockitoSession
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricNotificationDialogFactoryTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricNotificationDialogFactoryTest.java
index d2c6957..197cb84 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricNotificationDialogFactoryTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricNotificationDialogFactoryTest.java
@@ -33,9 +33,9 @@
import android.hardware.face.FaceManager;
import android.hardware.fingerprint.FingerprintManager;
import android.provider.Settings;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -53,7 +53,7 @@
import java.util.concurrent.ExecutionException;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
public class BiometricNotificationDialogFactoryTest extends SysuiTestCase {
@Rule
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricNotificationServiceTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricNotificationServiceTest.java
index a279d3e..20d9433 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricNotificationServiceTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricNotificationServiceTest.java
@@ -36,9 +36,9 @@
import android.hardware.fingerprint.FingerprintManager;
import android.os.Handler;
import android.os.UserHandle;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.keyguard.KeyguardUpdateMonitor;
@@ -58,7 +58,7 @@
import java.util.Optional;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
public class BiometricNotificationServiceTest extends SysuiTestCase {
@Rule
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsUtilsTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsUtilsTest.java
index 5b6aee6..d26ccbc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsUtilsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsUtilsTest.java
@@ -23,6 +23,7 @@
import android.hardware.fingerprint.FingerprintSensorProperties;
import android.view.Surface;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -33,11 +34,10 @@
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
-@RunWith(JUnit4.class)
+@RunWith(AndroidJUnit4.class)
@SmallTest
public class UdfpsUtilsTest extends SysuiTestCase {
@Rule
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/BiometricStatusRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/BiometricStatusRepositoryTest.kt
index b3e845f..d215047 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/BiometricStatusRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/BiometricStatusRepositoryTest.kt
@@ -29,6 +29,7 @@
import android.hardware.biometrics.events.AuthenticationAcquiredInfo
import android.hardware.biometrics.events.AuthenticationStartedInfo
import android.hardware.biometrics.events.AuthenticationStoppedInfo
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.biometrics.shared.model.AuthenticationReason
@@ -46,7 +47,6 @@
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
import org.mockito.Mock
import org.mockito.Mockito.verify
import org.mockito.junit.MockitoJUnit
@@ -54,7 +54,7 @@
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
-@RunWith(JUnit4::class)
+@RunWith(AndroidJUnit4::class)
class BiometricStatusRepositoryTest : SysuiTestCase() {
@JvmField @Rule var mockitoRule: MockitoRule = MockitoJUnit.rule()
@Mock private lateinit var biometricManager: BiometricManager
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/DisplayStateRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/DisplayStateRepositoryTest.kt
index eae953e..d9b7161 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/DisplayStateRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/DisplayStateRepositoryTest.kt
@@ -21,6 +21,7 @@
import android.view.Display.DEFAULT_DISPLAY
import android.view.DisplayInfo
import android.view.Surface
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.biometrics.data.repository.DisplayStateRepository
@@ -42,12 +43,11 @@
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
import org.mockito.Mockito.spy
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
-@RunWith(JUnit4::class)
+@RunWith(AndroidJUnit4::class)
class DisplayStateRepositoryTest : SysuiTestCase() {
private val display = mock<Display>()
private val testScope = TestScope(StandardTestDispatcher())
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/FacePropertyRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/FacePropertyRepositoryImplTest.kt
index f5e96c9..9c11405 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/FacePropertyRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/FacePropertyRepositoryImplTest.kt
@@ -26,6 +26,7 @@
import android.hardware.face.FaceManager
import android.hardware.face.FaceSensorPropertiesInternal
import android.hardware.face.IFaceAuthenticatorsRegisteredCallback
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.biometrics.shared.model.LockoutMode
@@ -46,7 +47,6 @@
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
import org.mockito.ArgumentCaptor
import org.mockito.Captor
import org.mockito.Mock
@@ -57,7 +57,7 @@
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
-@RunWith(JUnit4::class)
+@RunWith(AndroidJUnit4::class)
class FacePropertyRepositoryImplTest : SysuiTestCase() {
companion object {
private const val LOGICAL_CAMERA_ID_OUTER_FRONT = "0"
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/FaceSettingsRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/FaceSettingsRepositoryImplTest.kt
index 6391986..0209ab8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/FaceSettingsRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/FaceSettingsRepositoryImplTest.kt
@@ -19,6 +19,7 @@
import android.database.ContentObserver
import android.os.Handler
import android.provider.Settings.Secure.FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
@@ -35,7 +36,6 @@
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
import org.mockito.ArgumentMatchers.anyBoolean
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.Mock
@@ -47,7 +47,7 @@
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
-@RunWith(JUnit4::class)
+@RunWith(AndroidJUnit4::class)
class FaceSettingsRepositoryImplTest : SysuiTestCase() {
@JvmField @Rule var mockitoRule = MockitoJUnit.rule()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/FingerprintRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/FingerprintRepositoryImplTest.kt
index 7808c41..ff5a419f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/FingerprintRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/FingerprintRepositoryImplTest.kt
@@ -23,6 +23,7 @@
import android.hardware.fingerprint.FingerprintSensorProperties
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal
import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.biometrics.shared.model.FingerprintSensorType
@@ -38,7 +39,6 @@
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
import org.mockito.ArgumentCaptor
import org.mockito.Captor
import org.mockito.Mock
@@ -47,7 +47,7 @@
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
-@RunWith(JUnit4::class)
+@RunWith(AndroidJUnit4::class)
class FingerprintRepositoryImplTest : SysuiTestCase() {
@JvmField @Rule var mockitoRule = MockitoJUnit.rule()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/PromptRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/PromptRepositoryImplTest.kt
index 2682633..22971bc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/PromptRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/PromptRepositoryImplTest.kt
@@ -17,6 +17,7 @@
package com.android.systemui.biometrics.data.repository
import android.hardware.biometrics.PromptInfo
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.biometrics.AuthController
@@ -37,7 +38,6 @@
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
import org.mockito.ArgumentMatchers.eq
import org.mockito.Mock
import org.mockito.Mockito.verify
@@ -51,7 +51,7 @@
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
-@RunWith(JUnit4::class)
+@RunWith(AndroidJUnit4::class)
class PromptRepositoryImplTest : SysuiTestCase() {
@JvmField @Rule var mockitoRule = MockitoJUnit.rule()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/BiometricStatusInteractorImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/BiometricStatusInteractorImplTest.kt
index 4cff3e6..5d2d20c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/BiometricStatusInteractorImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/BiometricStatusInteractorImplTest.kt
@@ -19,6 +19,7 @@
import android.app.ActivityManager
import android.content.ComponentName
import android.hardware.biometrics.BiometricFingerprintConstants
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.app.activityTaskManager
import com.android.systemui.SysuiTestCase
@@ -37,13 +38,12 @@
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
import org.mockito.Mockito
import org.mockito.Mockito.`when`
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
-@RunWith(JUnit4::class)
+@RunWith(AndroidJUnit4::class)
class BiometricStatusInteractorImplTest : SysuiTestCase() {
private val kosmos = testKosmos()
private lateinit var underTest: BiometricStatusInteractorImpl
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/CredentialInteractorImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/CredentialInteractorImplTest.kt
index 8690d4e..4856f15 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/CredentialInteractorImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/CredentialInteractorImplTest.kt
@@ -4,6 +4,7 @@
import android.app.admin.DevicePolicyResourcesManager
import android.content.pm.UserInfo
import android.os.UserManager
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.internal.widget.LockPatternUtils
import com.android.internal.widget.LockscreenCredential
@@ -25,7 +26,6 @@
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.ArgumentMatchers.anyLong
import org.mockito.Mock
@@ -38,7 +38,7 @@
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
-@RunWith(JUnit4::class)
+@RunWith(AndroidJUnit4::class)
class CredentialInteractorImplTest : SysuiTestCase() {
@JvmField @Rule var mockitoRule = MockitoJUnit.rule()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/DisplayStateInteractorImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/DisplayStateInteractorImplTest.kt
index 31bdde2..f40b6b0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/DisplayStateInteractorImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/DisplayStateInteractorImplTest.kt
@@ -1,5 +1,6 @@
package com.android.systemui.biometrics.domain.interactor
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.biometrics.data.repository.FakeDisplayStateRepository
@@ -22,14 +23,13 @@
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
import org.mockito.Mock
import org.mockito.Mockito.verify
import org.mockito.junit.MockitoJUnit
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
-@RunWith(JUnit4::class)
+@RunWith(AndroidJUnit4::class)
class DisplayStateInteractorImplTest : SysuiTestCase() {
@JvmField @Rule var mockitoRule = MockitoJUnit.rule()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/LogContextInteractorImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/LogContextInteractorImplTest.kt
index 3f83ce3..a58efd3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/LogContextInteractorImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/LogContextInteractorImplTest.kt
@@ -19,6 +19,7 @@
import android.hardware.biometrics.AuthenticateOptions
import android.hardware.biometrics.IBiometricContextListener
import android.hardware.biometrics.IBiometricContextListener.FoldState
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
@@ -40,12 +41,11 @@
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
import org.mockito.junit.MockitoJUnit
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
-@RunWith(JUnit4::class)
+@RunWith(AndroidJUnit4::class)
class LogContextInteractorImplTest : SysuiTestCase() {
@JvmField @Rule var mockitoRule = MockitoJUnit.rule()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/PromptCredentialInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/PromptCredentialInteractorTest.kt
index c4d0d23..5a36376 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/PromptCredentialInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/PromptCredentialInteractorTest.kt
@@ -3,6 +3,7 @@
import android.hardware.biometrics.PromptContentViewWithMoreOptionsButton
import android.hardware.biometrics.PromptInfo
import android.hardware.biometrics.PromptVerticalListContentView
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.biometrics.data.repository.FakePromptRepository
@@ -29,7 +30,6 @@
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
import org.mockito.junit.MockitoJUnit
private const val USER_ID = 22
@@ -39,7 +39,7 @@
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
-@RunWith(JUnit4::class)
+@RunWith(AndroidJUnit4::class)
class PromptCredentialInteractorTest : SysuiTestCase() {
@JvmField @Rule var mockitoRule = MockitoJUnit.rule()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractorImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractorImplTest.kt
index 6e78e33..720f207 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractorImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractorImplTest.kt
@@ -22,6 +22,7 @@
import android.hardware.biometrics.PromptContentViewWithMoreOptionsButton
import android.hardware.biometrics.PromptInfo
import android.hardware.biometrics.PromptVerticalListContentView
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.internal.widget.LockPatternUtils
import com.android.systemui.SysuiTestCase
@@ -47,13 +48,12 @@
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
import org.mockito.Mock
import org.mockito.junit.MockitoJUnit
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
-@RunWith(JUnit4::class)
+@RunWith(AndroidJUnit4::class)
class PromptSelectorInteractorImplTest : SysuiTestCase() {
companion object {
private const val TITLE = "hey there"
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractorTest.kt
index 5e7adb7..3d63c5b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractorTest.kt
@@ -19,6 +19,7 @@
import android.graphics.Rect
import android.view.MotionEvent
import android.view.Surface
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.biometrics.AuthController
@@ -34,7 +35,6 @@
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
import org.mockito.ArgumentCaptor
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.Captor
@@ -44,7 +44,7 @@
import org.mockito.junit.MockitoJUnit
@SmallTest
-@RunWith(JUnit4::class)
+@RunWith(AndroidJUnit4::class)
class UdfpsOverlayInteractorTest : SysuiTestCase() {
@JvmField @Rule var mockitoRule = MockitoJUnit.rule()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/model/BiometricPromptRequestTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/model/BiometricPromptRequestTest.kt
index d10b935..08f139c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/model/BiometricPromptRequestTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/model/BiometricPromptRequestTest.kt
@@ -4,8 +4,10 @@
import android.hardware.biometrics.PromptContentItemBulletedText
import android.hardware.biometrics.PromptContentViewWithMoreOptionsButton
import android.hardware.biometrics.PromptVerticalListContentView
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.biometrics.Utils.toBitmap
import com.android.systemui.biometrics.fingerprintSensorPropertiesInternal
import com.android.systemui.biometrics.promptInfo
import com.android.systemui.biometrics.shared.model.BiometricModalities
@@ -15,19 +17,19 @@
import com.google.common.util.concurrent.MoreExecutors
import org.junit.Test
import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
private const val USER_ID = 2
private const val OPERATION_ID = 8L
private const val OP_PACKAGE_NAME = "biometric.testapp"
@SmallTest
-@RunWith(JUnit4::class)
+@RunWith(AndroidJUnit4::class)
class BiometricPromptRequestTest : SysuiTestCase() {
@Test
fun biometricRequestFromPromptInfo() {
val logoRes = R.drawable.ic_cake
+ val logoBitmapFromRes = context.getDrawable(logoRes).toBitmap()
val logoDescription = "test cake"
val title = "what"
val subtitle = "a"
@@ -44,6 +46,7 @@
BiometricPromptRequest.Biometric(
promptInfo(
logoRes = logoRes,
+ logoBitmap = logoBitmapFromRes,
logoDescription = logoDescription,
title = title,
subtitle = subtitle,
@@ -56,7 +59,8 @@
OP_PACKAGE_NAME,
)
- assertThat(request.logoRes).isEqualTo(logoRes)
+ assertThat(request.logoBitmap).isNotNull()
+ assertThat(request.logoBitmap!!.sameAs(logoBitmapFromRes)).isTrue()
assertThat(request.logoDescription).isEqualTo(logoDescription)
assertThat(request.title).isEqualTo(title)
assertThat(request.subtitle).isEqualTo(subtitle)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/shared/model/BiometricModalitiesTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/shared/model/BiometricModalitiesTest.kt
index 74c4313..4d8fafc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/shared/model/BiometricModalitiesTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/shared/model/BiometricModalitiesTest.kt
@@ -17,6 +17,7 @@
package com.android.systemui.biometrics.shared.model
import android.hardware.fingerprint.FingerprintSensorProperties
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.biometrics.faceSensorPropertiesInternal
@@ -24,10 +25,9 @@
import com.google.common.truth.Truth.assertThat
import org.junit.Test
import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
@SmallTest
-@RunWith(JUnit4::class)
+@RunWith(AndroidJUnit4::class)
class BiometricModalitiesTest : SysuiTestCase() {
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/udfps/BoundingBoxOverlapDetectorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/udfps/BoundingBoxOverlapDetectorTest.kt
index 95b72d5..f9bedc9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/udfps/BoundingBoxOverlapDetectorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/udfps/BoundingBoxOverlapDetectorTest.kt
@@ -21,12 +21,13 @@
import com.android.systemui.SysuiTestCase
import com.google.common.truth.Truth.assertThat
import org.junit.Test
+import platform.test.runner.parameterized.ParameterizedAndroidJunit4
+import platform.test.runner.parameterized.Parameters
+import platform.test.runner.parameterized.Parameter
import org.junit.runner.RunWith
-import org.junit.runners.Parameterized
-import org.junit.runners.Parameterized.Parameters
@SmallTest
-@RunWith(Parameterized::class)
+@RunWith(ParameterizedAndroidJunit4::class)
class BoundingBoxOverlapDetectorTest(val testCase: TestCase) : SysuiTestCase() {
val underTest = BoundingBoxOverlapDetector(1f)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/udfps/EllipseOverlapDetectorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/udfps/EllipseOverlapDetectorTest.kt
index 317141b..33ddbf1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/udfps/EllipseOverlapDetectorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/udfps/EllipseOverlapDetectorTest.kt
@@ -22,12 +22,13 @@
import com.android.systemui.biometrics.EllipseOverlapDetectorParams
import com.google.common.truth.Truth.assertThat
import org.junit.Test
+import platform.test.runner.parameterized.ParameterizedAndroidJunit4
+import platform.test.runner.parameterized.Parameters
+import platform.test.runner.parameterized.Parameter
import org.junit.runner.RunWith
-import org.junit.runners.Parameterized
-import org.junit.runners.Parameterized.Parameters
@SmallTest
-@RunWith(Parameterized::class)
+@RunWith(ParameterizedAndroidJunit4::class)
class EllipseOverlapDetectorTest(val testCase: TestCase) : SysuiTestCase() {
val underTest =
EllipseOverlapDetector(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/udfps/NormalizedTouchDataTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/udfps/NormalizedTouchDataTest.kt
index 3e5c43a..3863b3c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/udfps/NormalizedTouchDataTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/udfps/NormalizedTouchDataTest.kt
@@ -5,12 +5,13 @@
import com.android.systemui.SysuiTestCase
import com.google.common.truth.Truth.assertThat
import org.junit.Test
+import platform.test.runner.parameterized.ParameterizedAndroidJunit4
+import platform.test.runner.parameterized.Parameters
+import platform.test.runner.parameterized.Parameter
import org.junit.runner.RunWith
-import org.junit.runners.Parameterized
-import org.junit.runners.Parameterized.Parameters
@SmallTest
-@RunWith(Parameterized::class)
+@RunWith(ParameterizedAndroidJunit4::class)
class NormalizedTouchDataTest(val testCase: TestCase) : SysuiTestCase() {
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/udfps/SinglePointerTouchProcessorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/udfps/SinglePointerTouchProcessorTest.kt
index aff93bd..a4653e7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/udfps/SinglePointerTouchProcessorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/udfps/SinglePointerTouchProcessorTest.kt
@@ -27,12 +27,13 @@
import com.android.systemui.biometrics.shared.model.UdfpsOverlayParams
import com.google.common.truth.Truth.assertThat
import org.junit.Test
+import platform.test.runner.parameterized.ParameterizedAndroidJunit4
+import platform.test.runner.parameterized.Parameters
+import platform.test.runner.parameterized.Parameter
import org.junit.runner.RunWith
-import org.junit.runners.Parameterized
-import org.junit.runners.Parameterized.Parameters
@SmallTest
-@RunWith(Parameterized::class)
+@RunWith(ParameterizedAndroidJunit4::class)
class SinglePointerTouchProcessorTest(val testCase: TestCase) : SysuiTestCase() {
private val overlapDetector = FakeOverlapDetector()
private val underTest = SinglePointerTouchProcessor(overlapDetector)
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 ec2b104..4238254 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
@@ -32,6 +32,7 @@
import android.view.WindowMetrics
import android.view.layoutInflater
import android.view.windowManager
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.airbnb.lottie.LottieAnimationView
import com.android.keyguard.keyguardUpdateMonitor
@@ -61,7 +62,6 @@
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
import org.mockito.Mock
import org.mockito.Mockito
import org.mockito.Mockito.any
@@ -76,7 +76,7 @@
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
-@RunWith(JUnit4::class)
+@RunWith(AndroidJUnit4::class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
class SideFpsOverlayViewBinderTest : SysuiTestCase() {
private val kosmos = testKosmos()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/CredentialViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/CredentialViewModelTest.kt
index 9e804c1..e4c5cd4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/CredentialViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/CredentialViewModelTest.kt
@@ -1,5 +1,6 @@
package com.android.systemui.biometrics.ui.viewmodel
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.biometrics.data.repository.FakePromptRepository
@@ -19,7 +20,6 @@
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
private const val USER_ID = 9
private const val REQUEST_ID = 9L
@@ -27,7 +27,7 @@
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
-@RunWith(JUnit4::class)
+@RunWith(AndroidJUnit4::class)
class CredentialViewModelTest : SysuiTestCase() {
private val dispatcher = UnconfinedTestDispatcher()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/DeviceEntryUdfpsTouchOverlayViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/DeviceEntryUdfpsTouchOverlayViewModelTest.kt
index 1b6aaab..77ddd31 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/DeviceEntryUdfpsTouchOverlayViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/DeviceEntryUdfpsTouchOverlayViewModelTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.biometrics.ui.viewmodel
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.bouncer.data.repository.fakeKeyguardBouncerRepository
@@ -34,7 +35,6 @@
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
import org.mockito.ArgumentCaptor
import org.mockito.Captor
import org.mockito.Mockito.verify
@@ -42,7 +42,7 @@
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
-@RunWith(JUnit4::class)
+@RunWith(AndroidJUnit4::class)
class DeviceEntryUdfpsTouchOverlayViewModelTest : SysuiTestCase() {
private val kosmos =
testKosmos().apply {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptAuthStateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptAuthStateTest.kt
index 278a43e..3eb2ff3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptAuthStateTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptAuthStateTest.kt
@@ -16,16 +16,16 @@
package com.android.systemui.biometrics.ui.viewmodel
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.biometrics.shared.model.BiometricModality
import com.google.common.truth.Truth.assertThat
import org.junit.Test
import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
@SmallTest
-@RunWith(JUnit4::class)
+@RunWith(AndroidJUnit4::class)
class PromptAuthStateTest : SysuiTestCase() {
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptHistoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptHistoryImplTest.kt
index f9b590f..81132d7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptHistoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptHistoryImplTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.biometrics.ui.viewmodel
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.biometrics.shared.model.BiometricModality
@@ -23,10 +24,9 @@
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
@SmallTest
-@RunWith(JUnit4::class)
+@RunWith(AndroidJUnit4::class)
class PromptHistoryImplTest : SysuiTestCase() {
private lateinit var history: PromptHistoryImpl
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt
index 1167fce..7076954 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt
@@ -48,6 +48,7 @@
import com.android.systemui.SysuiTestCase
import com.android.systemui.biometrics.AuthController
import com.android.systemui.biometrics.UdfpsUtils
+import com.android.systemui.biometrics.Utils.toBitmap
import com.android.systemui.biometrics.data.repository.FakeBiometricStatusRepository
import com.android.systemui.biometrics.data.repository.FakeDisplayStateRepository
import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository
@@ -86,10 +87,12 @@
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
+import platform.test.runner.parameterized.ParameterizedAndroidJunit4
+import platform.test.runner.parameterized.Parameter
+import platform.test.runner.parameterized.Parameters
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
-import org.junit.runners.Parameterized
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.ArgumentMatchers.eq
import org.mockito.Mock
@@ -105,7 +108,7 @@
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
-@RunWith(Parameterized::class)
+@RunWith(ParameterizedAndroidJunit4::class)
internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCase() {
@JvmField @Rule var mockitoRule = MockitoJUnit.rule()
@@ -127,7 +130,7 @@
private val defaultLogoIcon = context.getDrawable(R.drawable.ic_android)
private val defaultLogoIconWithOverrides = context.getDrawable(R.drawable.ic_add)
private val logoResFromApp = R.drawable.ic_cake
- private val logoFromApp = context.getDrawable(logoResFromApp)
+ private val logoDrawableFromAppRes = context.getDrawable(logoResFromApp)
private val logoBitmapFromApp = Bitmap.createBitmap(400, 400, Bitmap.Config.RGB_565)
private val defaultLogoDescription = "Test Android App"
private val logoDescriptionFromApp = "Test Cake App"
@@ -221,7 +224,7 @@
context.setMockPackageManager(packageManager)
val resources = context.getOrCreateTestableResources()
- resources.addOverride(logoResFromApp, logoFromApp)
+ resources.addOverride(logoResFromApp, logoDrawableFromAppRes)
resources.addOverride(
R.array.biometric_dialog_package_names_for_logo_with_overrides,
arrayOf(packageNameForLogoWithOverrides)
@@ -1249,7 +1252,7 @@
@Test
@EnableFlags(FLAG_CUSTOM_BIOMETRIC_PROMPT, FLAG_CONSTRAINT_BP)
fun descriptionOverriddenByVerticalListContentView() =
- runGenericTest(contentView = promptContentView, description = "test description") {
+ runGenericTest(description = "test description", contentView = promptContentView) {
val contentView by collectLastValue(viewModel.contentView)
val description by collectLastValue(viewModel.description)
@@ -1261,8 +1264,8 @@
@EnableFlags(FLAG_CUSTOM_BIOMETRIC_PROMPT, FLAG_CONSTRAINT_BP)
fun descriptionOverriddenByContentViewWithMoreOptionsButton() =
runGenericTest(
- contentView = promptContentViewWithMoreOptionsButton,
- description = "test description"
+ description = "test description",
+ contentView = promptContentViewWithMoreOptionsButton
) {
val contentView by collectLastValue(viewModel.contentView)
val description by collectLastValue(viewModel.description)
@@ -1322,8 +1325,9 @@
@EnableFlags(FLAG_CUSTOM_BIOMETRIC_PROMPT, FLAG_CONSTRAINT_BP)
fun logo_resSetByApp() =
runGenericTest(logoRes = logoResFromApp) {
+ val expectedBitmap = context.getDrawable(logoResFromApp).toBitmap()
val logo by collectLastValue(viewModel.logo)
- assertThat(logo).isEqualTo(logoFromApp)
+ assertThat((logo as BitmapDrawable).bitmap.sameAs(expectedBitmap)).isTrue()
}
@Test
@@ -1436,7 +1440,8 @@
descriptionFromApp = description,
contentViewFromApp = contentView,
logoResFromApp = logoRes,
- logoBitmapFromApp = logoBitmap,
+ logoBitmapFromApp =
+ if (logoRes != -1) logoDrawableFromAppRes.toBitmap() else logoBitmap,
logoDescriptionFromApp = logoDescription,
packageName = packageName,
)
@@ -1476,7 +1481,7 @@
companion object {
@JvmStatic
- @Parameterized.Parameters(name = "{0}")
+ @Parameters(name = "{0}")
fun data(): Collection<TestCase> = singleModalityTestCases + coexTestCases
private val singleModalityTestCases =
@@ -1629,8 +1634,6 @@
) {
val info =
PromptInfo().apply {
- logoRes = logoResFromApp
- logoBitmap = logoBitmapFromApp
logoDescription = logoDescriptionFromApp
title = "t"
subtitle = "s"
@@ -1640,6 +1643,9 @@
isDeviceCredentialAllowed = allowCredentialFallback
isConfirmationRequested = requireConfirmation
}
+ if (logoBitmapFromApp != null) {
+ info.setLogo(logoResFromApp, logoBitmapFromApp)
+ }
setPrompt(
info,
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 b065393..3b2cf61 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
@@ -27,6 +27,7 @@
import android.view.WindowInsets
import android.view.WindowMetrics
import android.view.windowManager
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.airbnb.lottie.model.KeyPath
import com.android.keyguard.keyguardUpdateMonitor
@@ -62,7 +63,6 @@
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
import org.mockito.Mock
import org.mockito.Mockito.mock
import org.mockito.Mockito.spy
@@ -71,7 +71,7 @@
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
-@RunWith(JUnit4::class)
+@RunWith(AndroidJUnit4::class)
class SideFpsOverlayViewModelTest : SysuiTestCase() {
private val kosmos = testKosmos()
@JvmField @Rule var mockitoRule: MockitoRule = MockitoJUnit.rule()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/BroadcastDialogDelegateTest.java b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/BroadcastDialogDelegateTest.java
index 49f2043..7d4ee25 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/BroadcastDialogDelegateTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/BroadcastDialogDelegateTest.java
@@ -28,11 +28,11 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.widget.Button;
import android.widget.TextView;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.internal.logging.testing.UiEventLoggerFake;
@@ -58,7 +58,7 @@
import org.mockito.MockitoAnnotations;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
public class BroadcastDialogDelegateTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingInteractorTest.kt
index 8a1a082..4d7c499 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingInteractorTest.kt
@@ -16,8 +16,8 @@
package com.android.systemui.bluetooth.qsdialog
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession
import com.android.dx.mockito.inline.extended.StaticMockitoSession
@@ -44,7 +44,7 @@
@ExperimentalCoroutinesApi
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
class AudioSharingInteractorTest : SysuiTestCase() {
private val testDispatcher = UnconfinedTestDispatcher()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/BluetoothAutoOnInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/BluetoothAutoOnInteractorTest.kt
index 4949716..ac5ceb8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/BluetoothAutoOnInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/BluetoothAutoOnInteractorTest.kt
@@ -17,7 +17,7 @@
package com.android.systemui.bluetooth.qsdialog
import android.bluetooth.BluetoothAdapter
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.settingslib.bluetooth.LocalBluetoothManager
import com.android.systemui.SysuiTestCase
@@ -39,7 +39,7 @@
import org.mockito.junit.MockitoRule
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class BluetoothAutoOnInteractorTest : SysuiTestCase() {
@get:Rule val mockitoRule: MockitoRule = MockitoJUnit.rule()
private val testDispatcher = StandardTestDispatcher()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/BluetoothAutoOnRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/BluetoothAutoOnRepositoryTest.kt
index 85e2a8d..b7b2be4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/BluetoothAutoOnRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/BluetoothAutoOnRepositoryTest.kt
@@ -17,7 +17,7 @@
package com.android.systemui.bluetooth.qsdialog
import android.bluetooth.BluetoothAdapter
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.settingslib.bluetooth.BluetoothEventManager
import com.android.settingslib.bluetooth.LocalBluetoothManager
@@ -38,7 +38,7 @@
import org.mockito.junit.MockitoRule
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class BluetoothAutoOnRepositoryTest : SysuiTestCase() {
@get:Rule val mockitoRule: MockitoRule = MockitoJUnit.rule()
private val testDispatcher = StandardTestDispatcher()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/BluetoothStateInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/BluetoothStateInteractorTest.kt
index 6fe7d86..993cac7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/BluetoothStateInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/BluetoothStateInteractorTest.kt
@@ -16,8 +16,8 @@
package com.android.systemui.bluetooth.qsdialog
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.settingslib.bluetooth.LocalBluetoothAdapter
import com.android.settingslib.bluetooth.LocalBluetoothManager
@@ -38,7 +38,7 @@
import org.mockito.junit.MockitoRule
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
class BluetoothStateInteractorTest : SysuiTestCase() {
@get:Rule val mockitoRule: MockitoRule = MockitoJUnit.rule()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogDelegateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogDelegateTest.kt
index 7215619..d01fac3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogDelegateTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogDelegateTest.kt
@@ -17,7 +17,6 @@
package com.android.systemui.bluetooth.qsdialog
import android.graphics.drawable.Drawable
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.view.LayoutInflater
import android.view.View
@@ -27,6 +26,7 @@
import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.internal.logging.UiEventLogger
import com.android.settingslib.bluetooth.CachedBluetoothDevice
@@ -57,7 +57,7 @@
import org.mockito.junit.MockitoRule
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
class BluetoothTileDialogDelegateTest : SysuiTestCase() {
companion object {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogRepositoryTest.kt
index 4aa6209..1f3dcac 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogRepositoryTest.kt
@@ -17,8 +17,8 @@
package com.android.systemui.bluetooth.qsdialog
import android.bluetooth.BluetoothAdapter
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.settingslib.bluetooth.CachedBluetoothDevice
import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager
@@ -35,7 +35,7 @@
import org.mockito.junit.MockitoRule
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
class BluetoothTileDialogRepositoryTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogViewModelTest.kt
index 11f74c0..9abb85d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogViewModelTest.kt
@@ -18,11 +18,11 @@
import android.bluetooth.BluetoothAdapter
import android.platform.test.annotations.EnableFlags
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.view.View
import android.view.View.GONE
import android.view.View.VISIBLE
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.internal.logging.UiEventLogger
import com.android.settingslib.bluetooth.CachedBluetoothDevice
@@ -62,7 +62,7 @@
import org.mockito.junit.MockitoRule
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
@EnableFlags(Flags.FLAG_BLUETOOTH_QS_TILE_DIALOG_AUTO_ON_TOGGLE)
class BluetoothTileDialogViewModelTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemActionInteractorImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemActionInteractorImplTest.kt
deleted file mode 100644
index 762137b..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemActionInteractorImplTest.kt
+++ /dev/null
@@ -1,121 +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.bluetooth.qsdialog
-
-import android.bluetooth.BluetoothDevice
-import android.testing.AndroidTestingRunner
-import android.testing.TestableLooper
-import androidx.test.filters.SmallTest
-import com.android.settingslib.bluetooth.CachedBluetoothDevice
-import com.android.systemui.SysuiTestCase
-import com.android.systemui.kosmos.testDispatcher
-import com.android.systemui.kosmos.testScope
-import com.android.systemui.statusbar.phone.SystemUIDialog
-import com.android.systemui.testKosmos
-import com.android.systemui.util.mockito.whenever
-import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.test.UnconfinedTestDispatcher
-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.Mock
-import org.mockito.Mockito.verify
-import org.mockito.junit.MockitoJUnit
-import org.mockito.junit.MockitoRule
-
-@SmallTest
-@RunWith(AndroidTestingRunner::class)
-@TestableLooper.RunWithLooper(setAsMainLooper = true)
-@OptIn(ExperimentalCoroutinesApi::class)
-class DeviceItemActionInteractorImplTest : SysuiTestCase() {
- @get:Rule val mockitoRule: MockitoRule = MockitoJUnit.rule()
- private val kosmos = testKosmos().apply { testDispatcher = UnconfinedTestDispatcher() }
- private lateinit var actionInteractorImpl: DeviceItemActionInteractor
-
- @Mock private lateinit var dialog: SystemUIDialog
- @Mock private lateinit var cachedDevice: CachedBluetoothDevice
- @Mock private lateinit var device: BluetoothDevice
- @Mock private lateinit var deviceItem: DeviceItem
-
- @Before
- fun setUp() {
- actionInteractorImpl = kosmos.deviceItemActionInteractor
- whenever(deviceItem.cachedBluetoothDevice).thenReturn(cachedDevice)
- whenever(cachedDevice.address).thenReturn("ADDRESS")
- whenever(cachedDevice.device).thenReturn(device)
- }
-
- @Test
- fun testOnClick_connectedMedia_setActive() {
- with(kosmos) {
- testScope.runTest {
- whenever(deviceItem.type)
- .thenReturn(DeviceItemType.AVAILABLE_MEDIA_BLUETOOTH_DEVICE)
- actionInteractorImpl.onClick(deviceItem, dialog)
- verify(cachedDevice).setActive()
- verify(bluetoothTileDialogLogger)
- .logDeviceClick(
- cachedDevice.address,
- DeviceItemType.AVAILABLE_MEDIA_BLUETOOTH_DEVICE
- )
- }
- }
- }
-
- @Test
- fun testOnClick_activeMedia_disconnect() {
- with(kosmos) {
- testScope.runTest {
- whenever(deviceItem.type).thenReturn(DeviceItemType.ACTIVE_MEDIA_BLUETOOTH_DEVICE)
- actionInteractorImpl.onClick(deviceItem, dialog)
- verify(cachedDevice).disconnect()
- verify(bluetoothTileDialogLogger)
- .logDeviceClick(
- cachedDevice.address,
- DeviceItemType.ACTIVE_MEDIA_BLUETOOTH_DEVICE
- )
- }
- }
- }
-
- @Test
- fun testOnClick_connectedOtherDevice_disconnect() {
- with(kosmos) {
- testScope.runTest {
- whenever(deviceItem.type).thenReturn(DeviceItemType.CONNECTED_BLUETOOTH_DEVICE)
- actionInteractorImpl.onClick(deviceItem, dialog)
- verify(cachedDevice).disconnect()
- verify(bluetoothTileDialogLogger)
- .logDeviceClick(cachedDevice.address, DeviceItemType.CONNECTED_BLUETOOTH_DEVICE)
- }
- }
- }
-
- @Test
- fun testOnClick_saved_connect() {
- with(kosmos) {
- testScope.runTest {
- whenever(deviceItem.type).thenReturn(DeviceItemType.SAVED_BLUETOOTH_DEVICE)
- actionInteractorImpl.onClick(deviceItem, dialog)
- verify(cachedDevice).connect()
- verify(bluetoothTileDialogLogger)
- .logDeviceClick(cachedDevice.address, DeviceItemType.SAVED_BLUETOOTH_DEVICE)
- }
- }
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemActionInteractorKosmos.kt b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemActionInteractorKosmos.kt
index e8e37bc..5ff4634 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemActionInteractorKosmos.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemActionInteractorKosmos.kt
@@ -13,19 +13,28 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
package com.android.systemui.bluetooth.qsdialog
import com.android.internal.logging.uiEventLogger
+import com.android.settingslib.bluetooth.LocalBluetoothManager
+import com.android.systemui.animation.DialogTransitionAnimator
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.testDispatcher
+import com.android.systemui.plugins.activityStarter
import com.android.systemui.util.mockito.mock
val Kosmos.bluetoothTileDialogLogger: BluetoothTileDialogLogger by Kosmos.Fixture { mock {} }
+val Kosmos.localBluetoothManager: LocalBluetoothManager by Kosmos.Fixture { mock {} }
+
+val Kosmos.dialogTransitionAnimator: DialogTransitionAnimator by Kosmos.Fixture { mock {} }
+
val Kosmos.deviceItemActionInteractor: DeviceItemActionInteractor by
Kosmos.Fixture {
- DeviceItemActionInteractorImpl(
+ DeviceItemActionInteractor(
+ activityStarter,
+ dialogTransitionAnimator,
+ localBluetoothManager,
testDispatcher,
bluetoothTileDialogLogger,
uiEventLogger,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemActionInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemActionInteractorTest.kt
new file mode 100644
index 0000000..8246506
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemActionInteractorTest.kt
@@ -0,0 +1,459 @@
+/*
+ * 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.bluetooth.qsdialog
+
+import android.bluetooth.BluetoothDevice
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import androidx.test.filters.SmallTest
+import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession
+import com.android.dx.mockito.inline.extended.StaticMockitoSession
+import com.android.settingslib.bluetooth.BluetoothUtils
+import com.android.settingslib.bluetooth.CachedBluetoothDevice
+import com.android.settingslib.bluetooth.LeAudioProfile
+import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant
+import com.android.settingslib.bluetooth.LocalBluetoothProfileManager
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.kosmos.testDispatcher
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.plugins.activityStarter
+import com.android.systemui.statusbar.phone.SystemUIDialog
+import com.android.systemui.testKosmos
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import kotlinx.coroutines.test.runTest
+import org.junit.After
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers
+import org.mockito.Mock
+import org.mockito.Mockito
+import org.mockito.Mockito.verify
+import org.mockito.junit.MockitoJUnit
+import org.mockito.junit.MockitoRule
+import org.mockito.kotlin.whenever
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+@OptIn(ExperimentalCoroutinesApi::class)
+class DeviceItemActionInteractorTest : SysuiTestCase() {
+ @get:Rule val mockitoRule: MockitoRule = MockitoJUnit.rule()
+ private val kosmos = testKosmos().apply { testDispatcher = UnconfinedTestDispatcher() }
+ private lateinit var actionInteractorImpl: DeviceItemActionInteractor
+ private lateinit var mockitoSession: StaticMockitoSession
+ private lateinit var activeMediaDeviceItem: DeviceItem
+ private lateinit var notConnectedDeviceItem: DeviceItem
+ private lateinit var connectedMediaDeviceItem: DeviceItem
+ private lateinit var connectedOtherDeviceItem: DeviceItem
+ @Mock private lateinit var dialog: SystemUIDialog
+ @Mock private lateinit var profileManager: LocalBluetoothProfileManager
+ @Mock private lateinit var leAudioProfile: LeAudioProfile
+ @Mock private lateinit var assistantProfile: LocalBluetoothLeBroadcastAssistant
+ @Mock private lateinit var bluetoothDevice: BluetoothDevice
+ @Mock private lateinit var bluetoothDeviceGroupId2: BluetoothDevice
+ @Mock private lateinit var cachedBluetoothDevice: CachedBluetoothDevice
+
+ @Before
+ fun setUp() {
+ mockitoSession =
+ mockitoSession().initMocks(this).mockStatic(BluetoothUtils::class.java).startMocking()
+ activeMediaDeviceItem =
+ DeviceItem(
+ type = DeviceItemType.ACTIVE_MEDIA_BLUETOOTH_DEVICE,
+ cachedBluetoothDevice = cachedBluetoothDevice,
+ deviceName = DEVICE_NAME,
+ connectionSummary = DEVICE_CONNECTION_SUMMARY,
+ iconWithDescription = null,
+ background = null
+ )
+ notConnectedDeviceItem =
+ DeviceItem(
+ type = DeviceItemType.SAVED_BLUETOOTH_DEVICE,
+ cachedBluetoothDevice = cachedBluetoothDevice,
+ deviceName = DEVICE_NAME,
+ connectionSummary = DEVICE_CONNECTION_SUMMARY,
+ iconWithDescription = null,
+ background = null
+ )
+ connectedMediaDeviceItem =
+ DeviceItem(
+ type = DeviceItemType.AVAILABLE_MEDIA_BLUETOOTH_DEVICE,
+ cachedBluetoothDevice = cachedBluetoothDevice,
+ deviceName = DEVICE_NAME,
+ connectionSummary = DEVICE_CONNECTION_SUMMARY,
+ iconWithDescription = null,
+ background = null
+ )
+ connectedOtherDeviceItem =
+ DeviceItem(
+ type = DeviceItemType.CONNECTED_BLUETOOTH_DEVICE,
+ cachedBluetoothDevice = cachedBluetoothDevice,
+ deviceName = DEVICE_NAME,
+ connectionSummary = DEVICE_CONNECTION_SUMMARY,
+ iconWithDescription = null,
+ background = null
+ )
+ actionInteractorImpl = kosmos.deviceItemActionInteractor
+ }
+
+ @After
+ fun tearDown() {
+ mockitoSession.finishMocking()
+ }
+
+ @Test
+ fun testOnClick_connectedMedia_setActive() {
+ with(kosmos) {
+ testScope.runTest {
+ whenever(cachedBluetoothDevice.address).thenReturn(DEVICE_ADDRESS)
+ whenever(BluetoothUtils.isAudioSharingEnabled()).thenReturn(false)
+ actionInteractorImpl.onClick(connectedMediaDeviceItem, dialog)
+ verify(cachedBluetoothDevice).setActive()
+ verify(bluetoothTileDialogLogger)
+ .logDeviceClick(
+ cachedBluetoothDevice.address,
+ DeviceItemType.AVAILABLE_MEDIA_BLUETOOTH_DEVICE
+ )
+ }
+ }
+ }
+
+ @Test
+ fun testOnClick_activeMedia_disconnect() {
+ with(kosmos) {
+ testScope.runTest {
+ whenever(cachedBluetoothDevice.address).thenReturn(DEVICE_ADDRESS)
+ whenever(BluetoothUtils.isAudioSharingEnabled()).thenReturn(false)
+ actionInteractorImpl.onClick(activeMediaDeviceItem, dialog)
+ verify(cachedBluetoothDevice).disconnect()
+ verify(bluetoothTileDialogLogger)
+ .logDeviceClick(
+ cachedBluetoothDevice.address,
+ DeviceItemType.ACTIVE_MEDIA_BLUETOOTH_DEVICE
+ )
+ }
+ }
+ }
+
+ @Test
+ fun testOnClick_connectedOtherDevice_disconnect() {
+ with(kosmos) {
+ testScope.runTest {
+ whenever(cachedBluetoothDevice.address).thenReturn(DEVICE_ADDRESS)
+ whenever(BluetoothUtils.isAudioSharingEnabled()).thenReturn(false)
+ actionInteractorImpl.onClick(connectedOtherDeviceItem, dialog)
+ verify(cachedBluetoothDevice).disconnect()
+ verify(bluetoothTileDialogLogger)
+ .logDeviceClick(
+ cachedBluetoothDevice.address,
+ DeviceItemType.CONNECTED_BLUETOOTH_DEVICE
+ )
+ }
+ }
+ }
+
+ @Test
+ fun testOnClick_saved_connect() {
+ with(kosmos) {
+ testScope.runTest {
+ whenever(cachedBluetoothDevice.address).thenReturn(DEVICE_ADDRESS)
+ whenever(BluetoothUtils.isAudioSharingEnabled()).thenReturn(false)
+ actionInteractorImpl.onClick(notConnectedDeviceItem, dialog)
+ verify(cachedBluetoothDevice).connect()
+ verify(bluetoothTileDialogLogger)
+ .logDeviceClick(
+ cachedBluetoothDevice.address,
+ DeviceItemType.SAVED_BLUETOOTH_DEVICE
+ )
+ }
+ }
+ }
+
+ @Test
+ fun testOnClick_audioSharingDisabled_shouldNotLaunchSettings() {
+ with(kosmos) {
+ testScope.runTest {
+ whenever(cachedBluetoothDevice.address).thenReturn(DEVICE_ADDRESS)
+ whenever(BluetoothUtils.isAudioSharingEnabled()).thenReturn(false)
+
+ actionInteractorImpl.onClick(connectedMediaDeviceItem, dialog)
+ verify(activityStarter, Mockito.never())
+ .postStartActivityDismissingKeyguard(
+ ArgumentMatchers.any(),
+ ArgumentMatchers.anyInt(),
+ ArgumentMatchers.any()
+ )
+ }
+ }
+ }
+
+ @Test
+ fun testOnClick_inAudioSharing_clickedDeviceHasSource_shouldNotLaunchSettings() {
+ with(kosmos) {
+ testScope.runTest {
+ whenever(cachedBluetoothDevice.address).thenReturn(DEVICE_ADDRESS)
+ whenever(cachedBluetoothDevice.connectableProfiles)
+ .thenReturn(listOf(leAudioProfile))
+
+ whenever(BluetoothUtils.isAudioSharingEnabled()).thenReturn(true)
+ whenever(localBluetoothManager.profileManager).thenReturn(profileManager)
+ whenever(profileManager.leAudioProfile).thenReturn(leAudioProfile)
+ whenever(profileManager.leAudioBroadcastAssistantProfile)
+ .thenReturn(assistantProfile)
+
+ whenever(BluetoothUtils.isBroadcasting(ArgumentMatchers.any())).thenReturn(true)
+ whenever(
+ BluetoothUtils.hasConnectedBroadcastSource(
+ ArgumentMatchers.any(),
+ ArgumentMatchers.any()
+ )
+ )
+ .thenReturn(true)
+
+ actionInteractorImpl.onClick(connectedMediaDeviceItem, dialog)
+ verify(activityStarter, Mockito.never())
+ .postStartActivityDismissingKeyguard(
+ ArgumentMatchers.any(),
+ ArgumentMatchers.anyInt(),
+ ArgumentMatchers.any()
+ )
+ }
+ }
+ }
+
+ @Test
+ fun testOnClick_inAudioSharing_clickedDeviceNoSource_shouldLaunchSettings() {
+ with(kosmos) {
+ testScope.runTest {
+ whenever(cachedBluetoothDevice.address).thenReturn(DEVICE_ADDRESS)
+ whenever(cachedBluetoothDevice.device).thenReturn(bluetoothDevice)
+ whenever(cachedBluetoothDevice.connectableProfiles)
+ .thenReturn(listOf(leAudioProfile))
+
+ whenever(BluetoothUtils.isAudioSharingEnabled()).thenReturn(true)
+ whenever(localBluetoothManager.profileManager).thenReturn(profileManager)
+ whenever(profileManager.leAudioProfile).thenReturn(leAudioProfile)
+ whenever(profileManager.leAudioBroadcastAssistantProfile)
+ .thenReturn(assistantProfile)
+
+ whenever(BluetoothUtils.isBroadcasting(ArgumentMatchers.any())).thenReturn(true)
+ whenever(
+ BluetoothUtils.hasConnectedBroadcastSource(
+ ArgumentMatchers.any(),
+ ArgumentMatchers.any()
+ )
+ )
+ .thenReturn(false)
+
+ actionInteractorImpl.onClick(connectedMediaDeviceItem, dialog)
+ verify(activityStarter)
+ .postStartActivityDismissingKeyguard(
+ ArgumentMatchers.any(),
+ ArgumentMatchers.anyInt(),
+ ArgumentMatchers.any()
+ )
+ }
+ }
+ }
+
+ @Test
+ fun testOnClick_noConnectedLeDevice_shouldNotLaunchSettings() {
+ with(kosmos) {
+ testScope.runTest {
+ whenever(cachedBluetoothDevice.address).thenReturn(DEVICE_ADDRESS)
+
+ whenever(BluetoothUtils.isAudioSharingEnabled()).thenReturn(true)
+ whenever(localBluetoothManager.profileManager).thenReturn(profileManager)
+ whenever(profileManager.leAudioProfile).thenReturn(leAudioProfile)
+ whenever(profileManager.leAudioBroadcastAssistantProfile)
+ .thenReturn(assistantProfile)
+
+ actionInteractorImpl.onClick(notConnectedDeviceItem, dialog)
+ verify(activityStarter, Mockito.never())
+ .postStartActivityDismissingKeyguard(
+ ArgumentMatchers.any(),
+ ArgumentMatchers.anyInt(),
+ ArgumentMatchers.any()
+ )
+ }
+ }
+ }
+
+ @Test
+ fun testOnClick_hasOneConnectedLeDevice_clickedNonLe_shouldNotLaunchSettings() {
+ with(kosmos) {
+ testScope.runTest {
+ whenever(cachedBluetoothDevice.address).thenReturn(DEVICE_ADDRESS)
+
+ whenever(BluetoothUtils.isAudioSharingEnabled()).thenReturn(true)
+ whenever(localBluetoothManager.profileManager).thenReturn(profileManager)
+ whenever(profileManager.leAudioProfile).thenReturn(leAudioProfile)
+ whenever(profileManager.leAudioBroadcastAssistantProfile)
+ .thenReturn(assistantProfile)
+
+ whenever(
+ assistantProfile.getDevicesMatchingConnectionStates(ArgumentMatchers.any())
+ )
+ .thenReturn(listOf(bluetoothDevice))
+
+ actionInteractorImpl.onClick(notConnectedDeviceItem, dialog)
+ verify(activityStarter, Mockito.never())
+ .postStartActivityDismissingKeyguard(
+ ArgumentMatchers.any(),
+ ArgumentMatchers.anyInt(),
+ ArgumentMatchers.any()
+ )
+ }
+ }
+ }
+
+ @Test
+ fun testOnClick_hasOneConnectedLeDevice_clickedLe_shouldLaunchSettings() {
+ with(kosmos) {
+ testScope.runTest {
+ whenever(cachedBluetoothDevice.device).thenReturn(bluetoothDevice)
+ whenever(cachedBluetoothDevice.address).thenReturn(DEVICE_ADDRESS)
+ whenever(cachedBluetoothDevice.profiles).thenReturn(listOf(leAudioProfile))
+ whenever(leAudioProfile.isEnabled(ArgumentMatchers.any())).thenReturn(true)
+
+ whenever(BluetoothUtils.isAudioSharingEnabled()).thenReturn(true)
+ whenever(localBluetoothManager.profileManager).thenReturn(profileManager)
+ whenever(profileManager.leAudioProfile).thenReturn(leAudioProfile)
+ whenever(profileManager.leAudioBroadcastAssistantProfile)
+ .thenReturn(assistantProfile)
+
+ whenever(
+ assistantProfile.getDevicesMatchingConnectionStates(ArgumentMatchers.any())
+ )
+ .thenReturn(listOf(bluetoothDevice))
+
+ actionInteractorImpl.onClick(notConnectedDeviceItem, dialog)
+ verify(activityStarter)
+ .postStartActivityDismissingKeyguard(
+ ArgumentMatchers.any(),
+ ArgumentMatchers.anyInt(),
+ ArgumentMatchers.any()
+ )
+ }
+ }
+ }
+
+ @Test
+ fun testOnClick_hasOneConnectedLeDevice_clickedConnectedLe_shouldNotLaunchSettings() {
+ with(kosmos) {
+ testScope.runTest {
+ whenever(cachedBluetoothDevice.address).thenReturn(DEVICE_ADDRESS)
+
+ whenever(BluetoothUtils.isAudioSharingEnabled()).thenReturn(true)
+ whenever(localBluetoothManager.profileManager).thenReturn(profileManager)
+ whenever(profileManager.leAudioProfile).thenReturn(leAudioProfile)
+ whenever(profileManager.leAudioBroadcastAssistantProfile)
+ .thenReturn(assistantProfile)
+
+ whenever(
+ assistantProfile.getDevicesMatchingConnectionStates(ArgumentMatchers.any())
+ )
+ .thenReturn(listOf(bluetoothDevice))
+
+ actionInteractorImpl.onClick(connectedMediaDeviceItem, dialog)
+ verify(activityStarter, Mockito.never())
+ .postStartActivityDismissingKeyguard(
+ ArgumentMatchers.any(),
+ ArgumentMatchers.anyInt(),
+ ArgumentMatchers.any()
+ )
+ }
+ }
+ }
+
+ @Test
+ fun testOnClick_hasTwoConnectedLeDevice_clickedNotConnectedLe_shouldNotLaunchSettings() {
+ with(kosmos) {
+ testScope.runTest {
+ whenever(cachedBluetoothDevice.address).thenReturn(DEVICE_ADDRESS)
+
+ whenever(BluetoothUtils.isAudioSharingEnabled()).thenReturn(true)
+ whenever(localBluetoothManager.profileManager).thenReturn(profileManager)
+ whenever(profileManager.leAudioProfile).thenReturn(leAudioProfile)
+ whenever(profileManager.leAudioBroadcastAssistantProfile)
+ .thenReturn(assistantProfile)
+
+ whenever(
+ assistantProfile.getDevicesMatchingConnectionStates(ArgumentMatchers.any())
+ )
+ .thenReturn(listOf(bluetoothDevice, bluetoothDeviceGroupId2))
+ whenever(leAudioProfile.getGroupId(ArgumentMatchers.any())).thenAnswer {
+ val device = it.arguments.first() as BluetoothDevice
+ if (device == bluetoothDevice) GROUP_ID_1 else GROUP_ID_2
+ }
+
+ actionInteractorImpl.onClick(notConnectedDeviceItem, dialog)
+ verify(activityStarter, Mockito.never())
+ .postStartActivityDismissingKeyguard(
+ ArgumentMatchers.any(),
+ ArgumentMatchers.anyInt(),
+ ArgumentMatchers.any()
+ )
+ }
+ }
+ }
+
+ @Test
+ fun testOnClick_hasTwoConnectedLeDevice_clickedConnectedLe_shouldLaunchSettings() {
+ with(kosmos) {
+ testScope.runTest {
+ whenever(cachedBluetoothDevice.device).thenReturn(bluetoothDevice)
+ whenever(cachedBluetoothDevice.address).thenReturn(DEVICE_ADDRESS)
+ whenever(cachedBluetoothDevice.profiles).thenReturn(listOf(leAudioProfile))
+ whenever(leAudioProfile.isEnabled(ArgumentMatchers.any())).thenReturn(true)
+
+ whenever(BluetoothUtils.isAudioSharingEnabled()).thenReturn(true)
+ whenever(localBluetoothManager.profileManager).thenReturn(profileManager)
+ whenever(profileManager.leAudioProfile).thenReturn(leAudioProfile)
+ whenever(profileManager.leAudioBroadcastAssistantProfile)
+ .thenReturn(assistantProfile)
+
+ whenever(
+ assistantProfile.getDevicesMatchingConnectionStates(ArgumentMatchers.any())
+ )
+ .thenReturn(listOf(bluetoothDevice, bluetoothDeviceGroupId2))
+ whenever(leAudioProfile.getGroupId(ArgumentMatchers.any())).thenAnswer {
+ val device = it.arguments.first() as BluetoothDevice
+ if (device == bluetoothDevice) GROUP_ID_1 else GROUP_ID_2
+ }
+
+ actionInteractorImpl.onClick(connectedMediaDeviceItem, dialog)
+ verify(activityStarter)
+ .postStartActivityDismissingKeyguard(
+ ArgumentMatchers.any(),
+ ArgumentMatchers.anyInt(),
+ ArgumentMatchers.any()
+ )
+ }
+ }
+ }
+
+ private companion object {
+ const val DEVICE_NAME = "device"
+ const val DEVICE_CONNECTION_SUMMARY = "active"
+ const val DEVICE_ADDRESS = "address"
+ const val GROUP_ID_1 = 1
+ const val GROUP_ID_2 = 2
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemFactoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemFactoryTest.kt
index 4bcd9a9..a27ccc6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemFactoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemFactoryTest.kt
@@ -22,8 +22,8 @@
import android.media.AudioManager
import android.platform.test.annotations.DisableFlags
import android.platform.test.annotations.EnableFlags
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.settingslib.bluetooth.CachedBluetoothDevice
import com.android.settingslib.flags.Flags
@@ -39,7 +39,7 @@
import org.mockito.junit.MockitoRule
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
class DeviceItemFactoryTest : SysuiTestCase() {
@get:Rule val mockitoRule: MockitoRule = MockitoJUnit.rule()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemInteractorTest.kt
index 2b4f950..7f7abaf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemInteractorTest.kt
@@ -20,8 +20,8 @@
import android.bluetooth.BluetoothDevice
import android.content.Context
import android.media.AudioManager
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.settingslib.bluetooth.CachedBluetoothDevice
import com.android.settingslib.bluetooth.LocalBluetoothManager
@@ -43,7 +43,7 @@
import org.mockito.junit.MockitoRule
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
class DeviceItemInteractorTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/helper/BouncerSceneLayoutTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/helper/BouncerSceneLayoutTest.kt
index ca95822..923687b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/helper/BouncerSceneLayoutTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/helper/BouncerSceneLayoutTest.kt
@@ -25,11 +25,13 @@
import com.google.common.truth.Truth.assertThat
import java.util.Locale
import org.junit.Test
+import platform.test.runner.parameterized.ParameterizedAndroidJunit4
+import platform.test.runner.parameterized.Parameter
+import platform.test.runner.parameterized.Parameters
import org.junit.runner.RunWith
-import org.junit.runners.Parameterized
@SmallTest
-@RunWith(Parameterized::class)
+@RunWith(ParameterizedAndroidJunit4::class)
class BouncerSceneLayoutTest : SysuiTestCase() {
data object Phone :
@@ -79,7 +81,7 @@
companion object {
@JvmStatic
- @Parameterized.Parameters(name = "{0}")
+ @Parameters(name = "{0}")
fun testCases() =
listOf(
Phone to
@@ -158,7 +160,7 @@
}
}
- @Parameterized.Parameter @JvmField var testCase: TestCase? = null
+ @Parameter @JvmField var testCase: TestCase? = null
@Test
fun calculateLayout() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/broadcast/BroadcastSenderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/broadcast/BroadcastSenderTest.kt
index 8e81727..1e9f855 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/broadcast/BroadcastSenderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/broadcast/BroadcastSenderTest.kt
@@ -20,7 +20,7 @@
import android.content.Intent
import android.os.Bundle
import android.os.UserHandle
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.util.concurrency.FakeExecutor
@@ -34,7 +34,7 @@
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
class BroadcastSenderTest : SysuiTestCase() {
@@ -138,4 +138,4 @@
verification.invoke()
assertThat(wakeLock.isHeld).isFalse()
}
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/broadcast/PendingRemovalStoreTest.kt b/packages/SystemUI/tests/src/com/android/systemui/broadcast/PendingRemovalStoreTest.kt
index 43d2cb8..c693ecc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/broadcast/PendingRemovalStoreTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/broadcast/PendingRemovalStoreTest.kt
@@ -2,7 +2,7 @@
import android.content.BroadcastReceiver
import android.os.UserHandle
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.broadcast.logging.BroadcastDispatcherLogger
@@ -14,7 +14,7 @@
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
class PendingRemovalStoreTest : SysuiTestCase() {
@@ -78,4 +78,4 @@
assertThat(store.isPendingRemoval(receiverOne, user)).isTrue()
assertThat(store.isPendingRemoval(receiverTwo, user)).isFalse()
}
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/broadcast/UserBroadcastDispatcherTest.kt b/packages/SystemUI/tests/src/com/android/systemui/broadcast/UserBroadcastDispatcherTest.kt
index 582f301..d878352 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/broadcast/UserBroadcastDispatcherTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/broadcast/UserBroadcastDispatcherTest.kt
@@ -21,8 +21,8 @@
import android.content.IntentFilter
import android.os.Handler
import android.os.UserHandle
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import com.android.systemui.SysuiTestCase
import com.android.systemui.broadcast.logging.BroadcastDispatcherLogger
@@ -43,7 +43,7 @@
import org.mockito.MockitoAnnotations
import java.util.concurrent.Executor
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@TestableLooper.RunWithLooper
@SmallTest
class UserBroadcastDispatcherTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/camera/CameraGestureHelperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/camera/CameraGestureHelperTest.kt
index 669795b..bea0db6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/camera/CameraGestureHelperTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/camera/CameraGestureHelperTest.kt
@@ -24,6 +24,7 @@
import android.content.pm.ActivityInfo
import android.content.pm.PackageManager
import android.content.pm.ResolveInfo
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.ActivityIntentHelper
import com.android.systemui.SysuiTestCase
@@ -41,7 +42,6 @@
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
import org.mockito.Mock
import org.mockito.Mockito.any
import org.mockito.Mockito.anyInt
@@ -50,7 +50,7 @@
import org.mockito.Mockito.`when` as whenever
@SmallTest
-@RunWith(JUnit4::class)
+@RunWith(AndroidJUnit4::class)
class CameraGestureHelperTest : SysuiTestCase() {
@Mock
diff --git a/packages/SystemUI/tests/src/com/android/systemui/camera/CameraIntentsTest.kt b/packages/SystemUI/tests/src/com/android/systemui/camera/CameraIntentsTest.kt
index 1e522fc..3494024 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/camera/CameraIntentsTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/camera/CameraIntentsTest.kt
@@ -17,8 +17,8 @@
package com.android.systemui.camera
import android.content.Intent
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
-import android.testing.AndroidTestingRunner
import com.android.systemui.SysuiTestCase
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
@@ -26,7 +26,7 @@
import org.junit.runner.RunWith
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class CameraIntentsTest : SysuiTestCase() {
companion object {
val VALID_SECURE_INTENT = Intent(CameraIntents.DEFAULT_SECURE_CAMERA_INTENT_ACTION)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/charging/WiredChargingRippleControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/charging/WiredChargingRippleControllerTest.kt
index 11756d5..034bab8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/charging/WiredChargingRippleControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/charging/WiredChargingRippleControllerTest.kt
@@ -17,11 +17,11 @@
package com.android.systemui.charging
import android.graphics.Rect
-import android.testing.AndroidTestingRunner
import android.view.Surface
import android.view.View
import android.view.WindowManager
import android.view.WindowMetrics
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.internal.logging.UiEventLogger
import com.android.systemui.res.R
@@ -49,7 +49,7 @@
import org.mockito.MockitoAnnotations
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class WiredChargingRippleControllerTest : SysuiTestCase() {
private lateinit var controller: WiredChargingRippleController
@Mock private lateinit var commandRegistry: CommandRegistry
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineClassifierTest.java
index 6afbde0..88bfcf0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineClassifierTest.java
@@ -29,10 +29,10 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import android.testing.AndroidTestingRunner;
import android.view.MotionEvent;
import android.view.accessibility.AccessibilityManager;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.internal.logging.MetricsLogger;
@@ -58,7 +58,7 @@
import java.util.Set;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
public class BrightLineClassifierTest extends SysuiTestCase {
private BrightLineFalsingManager mBrightLineFalsingManager;
@Mock
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineFalsingManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineFalsingManagerTest.java
index 6e00b70..ec8cc4d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineFalsingManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineFalsingManagerTest.java
@@ -25,10 +25,10 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import android.testing.AndroidTestingRunner;
import android.view.MotionEvent;
import android.view.accessibility.AccessibilityManager;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.internal.logging.MetricsLogger;
@@ -53,7 +53,7 @@
import java.util.Set;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
public class BrightLineFalsingManagerTest extends SysuiTestCase {
private BrightLineFalsingManager mBrightLineFalsingManager;
@Mock
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/DiagonalClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/DiagonalClassifierTest.java
index 14dcd58..8e1be41 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/DiagonalClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/DiagonalClassifierTest.java
@@ -24,8 +24,8 @@
import static org.mockito.Mockito.when;
-import android.testing.AndroidTestingRunner;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.util.DeviceConfigProxyFake;
@@ -38,7 +38,7 @@
import org.mockito.MockitoAnnotations;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
public class DiagonalClassifierTest extends ClassifierTest {
// Next variable is not actually five, but is very close. 5 degrees is currently the value
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/DistanceClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/DistanceClassifierTest.java
index ab6d5b7..cbfecee 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/DistanceClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/DistanceClassifierTest.java
@@ -21,8 +21,8 @@
import static com.google.common.truth.Truth.assertThat;
-import android.testing.AndroidTestingRunner;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.util.DeviceConfigProxyFake;
@@ -33,7 +33,7 @@
import org.junit.runner.RunWith;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
public class DistanceClassifierTest extends ClassifierTest {
private FalsingDataProvider mDataProvider;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/DoubleTapClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/DoubleTapClassifierTest.java
index 2ceee6d..9289867 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/DoubleTapClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/DoubleTapClassifierTest.java
@@ -22,9 +22,9 @@
import static org.mockito.ArgumentMatchers.anyList;
import static org.mockito.Mockito.when;
-import android.testing.AndroidTestingRunner;
import android.view.MotionEvent;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import org.junit.After;
@@ -38,7 +38,7 @@
import java.util.List;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
public class DoubleTapClassifierTest extends ClassifierTest {
private static final int TOUCH_SLOP = 100;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingA11yDelegateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingA11yDelegateTest.kt
index 2c904e7..8e4bec3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingA11yDelegateTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingA11yDelegateTest.kt
@@ -16,10 +16,10 @@
package com.android.systemui.classifier
-import android.testing.AndroidTestingRunner
import android.view.View
import android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK
import android.view.accessibility.AccessibilityNodeInfo.ACTION_LONG_CLICK
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import org.junit.Before
@@ -31,7 +31,7 @@
import org.mockito.MockitoAnnotations
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class FalsingA11yDelegateTest : SysuiTestCase() {
@Mock lateinit var falsingCollector: FalsingCollector
@Mock lateinit var view: View
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 5361cef..5d0bfd7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingCollectorImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingCollectorImplTest.java
@@ -25,11 +25,11 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.KeyEvent;
import android.view.MotionEvent;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.keyguard.KeyguardUpdateMonitor;
@@ -66,7 +66,7 @@
import org.mockito.MockitoAnnotations;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
public class FalsingCollectorImplTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingDataProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingDataProviderTest.java
index 057b0a1..49c6239 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingDataProviderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingDataProviderTest.java
@@ -25,11 +25,11 @@
import static org.mockito.Mockito.when;
import android.hardware.devicestate.DeviceStateManager.FoldStateListener;
-import android.testing.AndroidTestingRunner;
import android.util.DisplayMetrics;
import android.view.KeyEvent;
import android.view.MotionEvent;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.classifier.FalsingDataProvider.GestureFinalizedListener;
@@ -46,7 +46,7 @@
import java.util.List;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
public class FalsingDataProviderTest extends ClassifierTest {
private FalsingDataProvider mDataProvider;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/HistoryTrackerTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/HistoryTrackerTest.java
index 38355c7..8e19a1f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/HistoryTrackerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/HistoryTrackerTest.java
@@ -18,8 +18,8 @@
import static com.google.common.truth.Truth.assertThat;
-import android.testing.AndroidTestingRunner;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -33,7 +33,7 @@
import java.util.Collections;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
public class HistoryTrackerTest extends SysuiTestCase {
private FakeSystemClock mSystemClock = new FakeSystemClock();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/PointerCountClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/PointerCountClassifierTest.java
index b8ea062..352a25c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/PointerCountClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/PointerCountClassifierTest.java
@@ -23,9 +23,9 @@
import static org.mockito.ArgumentMatchers.anyDouble;
import static org.mockito.ArgumentMatchers.anyInt;
-import android.testing.AndroidTestingRunner;
import android.view.MotionEvent;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import org.junit.After;
@@ -34,7 +34,7 @@
import org.junit.runner.RunWith;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
public class PointerCountClassifierTest extends ClassifierTest {
private FalsingClassifier mClassifier;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/ProximityClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/ProximityClassifierTest.java
index 1c3922a..f965a11 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/ProximityClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/ProximityClassifierTest.java
@@ -24,9 +24,9 @@
import static org.mockito.Mockito.when;
-import android.testing.AndroidTestingRunner;
import android.view.MotionEvent;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.plugins.FalsingManager;
@@ -40,7 +40,7 @@
import org.mockito.MockitoAnnotations;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
public class ProximityClassifierTest extends ClassifierTest {
private static final long NS_PER_MS = 1000000;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/SingleTapClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/SingleTapClassifierTest.java
index e3c800e..65e9088 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/SingleTapClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/SingleTapClassifierTest.java
@@ -20,9 +20,9 @@
import static org.mockito.Mockito.when;
-import android.testing.AndroidTestingRunner;
import android.view.MotionEvent;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import org.junit.After;
@@ -36,7 +36,7 @@
import java.util.List;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
public class SingleTapClassifierTest extends ClassifierTest {
private static final int TOUCH_SLOP = 100;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/TimeLimitedInputEventBufferTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/TimeLimitedInputEventBufferTest.java
index ad7afa3..9a27f38 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/TimeLimitedInputEventBufferTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/TimeLimitedInputEventBufferTest.java
@@ -19,11 +19,11 @@
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
-import android.testing.AndroidTestingRunner;
import android.view.InputEvent;
import android.view.KeyEvent;
import android.view.MotionEvent;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -35,7 +35,7 @@
import org.mockito.MockitoAnnotations;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
public class TimeLimitedInputEventBufferTest extends SysuiTestCase {
private static final long MAX_AGE_MS = 100;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/TypeClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/TypeClassifierTest.java
index 588edb7..80c44e2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/TypeClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/TypeClassifierTest.java
@@ -33,8 +33,8 @@
import static org.mockito.Mockito.when;
-import android.testing.AndroidTestingRunner;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import org.junit.Before;
@@ -44,7 +44,7 @@
import org.mockito.MockitoAnnotations;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
public class TypeClassifierTest extends ClassifierTest {
@Mock
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/ZigZagClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/ZigZagClassifierTest.java
index ae2b8bb..1fe7268 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/ZigZagClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/ZigZagClassifierTest.java
@@ -20,8 +20,8 @@
import static com.google.common.truth.Truth.assertThat;
-import android.testing.AndroidTestingRunner;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.util.DeviceConfigProxyFake;
@@ -34,7 +34,7 @@
import java.util.Random;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
public class ZigZagClassifierTest extends ClassifierTest {
private FalsingClassifier mClassifier;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardModelTest.kt
index c0dada4..5d76e32 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardModelTest.kt
@@ -22,8 +22,8 @@
import android.graphics.Bitmap
import android.net.Uri
import android.os.PersistableBundle
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
-import androidx.test.runner.AndroidJUnit4
import com.android.systemui.SysuiTestCase
import com.android.systemui.util.mockito.whenever
import java.io.IOException
diff --git a/packages/SystemUI/tests/src/com/android/systemui/common/coroutine/CoroutineResultTest.kt b/packages/SystemUI/tests/src/com/android/systemui/common/coroutine/CoroutineResultTest.kt
index d552c9d..de07cda 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/common/coroutine/CoroutineResultTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/common/coroutine/CoroutineResultTest.kt
@@ -14,7 +14,7 @@
package com.android.systemui.common.coroutine
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.google.common.truth.Truth.assertThat
@@ -28,7 +28,7 @@
/** atest SystemUITests:CoroutineResultTest */
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class CoroutineResultTest : SysuiTestCase() {
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/common/ui/view/LongPressHandlingViewInteractionHandlerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/common/ui/view/LongPressHandlingViewInteractionHandlerTest.kt
index 2f4fc96..bb400f2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/common/ui/view/LongPressHandlingViewInteractionHandlerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/common/ui/view/LongPressHandlingViewInteractionHandlerTest.kt
@@ -18,6 +18,7 @@
package com.android.systemui.common.ui.view
import android.view.ViewConfiguration
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.common.ui.view.LongPressHandlingViewInteractionHandler.MotionEventModel
@@ -33,7 +34,6 @@
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
import org.mockito.Mock
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
@@ -41,7 +41,7 @@
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
-@RunWith(JUnit4::class)
+@RunWith(AndroidJUnit4::class)
class LongPressHandlingViewInteractionHandlerTest : SysuiTestCase() {
@Mock private lateinit var postDelayed: (Runnable, Long) -> DisposableHandle
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 4c4205e..cecb525 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
@@ -25,12 +25,12 @@
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.SeekBar;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -49,7 +49,7 @@
* Tests for {@link SeekBarWithIconButtonsView}
*/
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper
public class SeekBarWithIconButtonsViewTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/complication/ComplicationCollectionLiveDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/complication/ComplicationCollectionLiveDataTest.java
index 288f3b6..ed21474 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/complication/ComplicationCollectionLiveDataTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/complication/ComplicationCollectionLiveDataTest.java
@@ -21,10 +21,10 @@
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import androidx.lifecycle.Observer;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -48,7 +48,7 @@
import java.util.HashSet;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
public class ComplicationCollectionLiveDataTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/complication/ComplicationHostViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/complication/ComplicationHostViewControllerTest.java
index c43df17..dd3f991 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/complication/ComplicationHostViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/complication/ComplicationHostViewControllerTest.java
@@ -24,13 +24,13 @@
import android.os.UserHandle;
import android.provider.Settings;
-import android.testing.AndroidTestingRunner;
import android.view.View;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.Observer;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -51,7 +51,7 @@
import java.util.HashSet;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
public class ComplicationHostViewControllerTest extends SysuiTestCase {
@Mock
ConstraintLayout mComplicationHostView;
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 baaeee1..383e0fa 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/complication/ComplicationLayoutEngineTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/complication/ComplicationLayoutEngineTest.java
@@ -22,10 +22,10 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import android.testing.AndroidTestingRunner;
import android.view.View;
import androidx.constraintlayout.widget.ConstraintLayout;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -48,7 +48,7 @@
import java.util.stream.Collectors;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
public class ComplicationLayoutEngineTest extends SysuiTestCase {
@Mock
ConstraintLayout mLayout;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/complication/ComplicationLayoutParamsTest.java b/packages/SystemUI/tests/src/com/android/systemui/complication/ComplicationLayoutParamsTest.java
index a23e9e4..12cb8a6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/complication/ComplicationLayoutParamsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/complication/ComplicationLayoutParamsTest.java
@@ -21,8 +21,8 @@
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
-import android.testing.AndroidTestingRunner;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -36,7 +36,7 @@
import java.util.function.Consumer;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
public class ComplicationLayoutParamsTest extends SysuiTestCase {
/**
* Ensures ComplicationLayoutParams cannot be constructed with improper position or direction.
diff --git a/packages/SystemUI/tests/src/com/android/systemui/complication/ComplicationTypesUpdaterTest.java b/packages/SystemUI/tests/src/com/android/systemui/complication/ComplicationTypesUpdaterTest.java
index 8cd23b2..d728517 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/complication/ComplicationTypesUpdaterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/complication/ComplicationTypesUpdaterTest.java
@@ -25,8 +25,8 @@
import android.database.ContentObserver;
import android.os.UserHandle;
import android.provider.Settings;
-import android.testing.AndroidTestingRunner;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.settingslib.dream.DreamBackend;
@@ -50,7 +50,7 @@
import java.util.HashSet;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
public class ComplicationTypesUpdaterTest extends SysuiTestCase {
@Mock
private Context mContext;
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 e23e1f4..1e80233 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/complication/ComplicationUtilsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/complication/ComplicationUtilsTest.java
@@ -29,8 +29,8 @@
import static com.google.common.truth.Truth.assertThat;
-import android.testing.AndroidTestingRunner;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.settingslib.dream.DreamBackend;
@@ -45,7 +45,7 @@
import java.util.Set;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
public class ComplicationUtilsTest extends SysuiTestCase {
@Test
public void testConvertComplicationType() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/complication/ComplicationViewModelTransformerTest.java b/packages/SystemUI/tests/src/com/android/systemui/complication/ComplicationViewModelTransformerTest.java
index 09675e2..98b119a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/complication/ComplicationViewModelTransformerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/complication/ComplicationViewModelTransformerTest.java
@@ -21,9 +21,9 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import android.testing.AndroidTestingRunner;
import androidx.lifecycle.ViewModel;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -38,7 +38,7 @@
import org.mockito.MockitoAnnotations;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
public class ComplicationViewModelTransformerTest extends SysuiTestCase {
@Mock
ComplicationViewModelComponent.Factory mFactory;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/complication/DreamClockTimeComplicationTest.java b/packages/SystemUI/tests/src/com/android/systemui/complication/DreamClockTimeComplicationTest.java
index b9aa4c6..22ab499 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/complication/DreamClockTimeComplicationTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/complication/DreamClockTimeComplicationTest.java
@@ -23,9 +23,9 @@
import static org.mockito.Mockito.when;
import android.content.Context;
-import android.testing.AndroidTestingRunner;
import android.view.View;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.internal.logging.UiEventLogger;
@@ -42,7 +42,7 @@
import org.mockito.MockitoAnnotations;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
public class DreamClockTimeComplicationTest extends SysuiTestCase {
@SuppressWarnings("HidingField")
@Mock
diff --git a/packages/SystemUI/tests/src/com/android/systemui/complication/DreamHomeControlsComplicationTest.java b/packages/SystemUI/tests/src/com/android/systemui/complication/DreamHomeControlsComplicationTest.java
index 18bd960b..ddf69b5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/complication/DreamHomeControlsComplicationTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/complication/DreamHomeControlsComplicationTest.java
@@ -29,9 +29,9 @@
import android.content.ComponentName;
import android.content.res.Resources;
-import android.testing.AndroidTestingRunner;
import android.view.View;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.internal.logging.UiEventLogger;
@@ -62,7 +62,7 @@
import java.util.Optional;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
public class DreamHomeControlsComplicationTest extends SysuiTestCase {
@Mock
private DreamHomeControlsComplication mComplication;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/complication/DreamMediaEntryComplicationTest.java b/packages/SystemUI/tests/src/com/android/systemui/complication/DreamMediaEntryComplicationTest.java
index 05b4a41..3a856a0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/complication/DreamMediaEntryComplicationTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/complication/DreamMediaEntryComplicationTest.java
@@ -26,10 +26,10 @@
import android.app.PendingIntent;
import android.content.Intent;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.View;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.ActivityIntentHelper;
@@ -51,7 +51,7 @@
import org.mockito.MockitoAnnotations;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper
public class DreamMediaEntryComplicationTest extends SysuiTestCase {
@Mock
diff --git a/packages/SystemUI/tests/src/com/android/systemui/complication/SmartSpaceComplicationTest.java b/packages/SystemUI/tests/src/com/android/systemui/complication/SmartSpaceComplicationTest.java
index 87de865..6c354ef 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/complication/SmartSpaceComplicationTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/complication/SmartSpaceComplicationTest.java
@@ -24,9 +24,9 @@
import static org.mockito.Mockito.when;
import android.app.smartspace.SmartspaceTarget;
-import android.testing.AndroidTestingRunner;
import android.view.View;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -52,7 +52,7 @@
import java.util.Set;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
public class SmartSpaceComplicationTest extends SysuiTestCase {
@Mock
diff --git a/packages/SystemUI/tests/src/com/android/systemui/compose/ComposeInitializerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/compose/ComposeInitializerTest.kt
index 03e4f9a..c2fe009 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/compose/ComposeInitializerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/compose/ComposeInitializerTest.kt
@@ -17,10 +17,10 @@
package com.android.systemui.compose
import android.content.Context
-import android.testing.AndroidTestingRunner
import android.testing.ViewUtils
import android.widget.FrameLayout
import androidx.compose.ui.platform.ComposeView
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.google.common.truth.Truth.assertThat
@@ -28,7 +28,7 @@
import org.junit.runner.RunWith
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class ComposeInitializerTest : SysuiTestCase() {
@Test
fun testCanAddComposeViewInInitializedWindow() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/CustomIconCacheTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/CustomIconCacheTest.kt
index 4d0f2ed..28e0cff 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/CustomIconCacheTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/CustomIconCacheTest.kt
@@ -18,7 +18,7 @@
import android.content.ComponentName
import android.graphics.drawable.Icon
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import org.junit.Assert.assertNull
@@ -30,7 +30,7 @@
import org.mockito.MockitoAnnotations
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class CustomIconCacheTest : SysuiTestCase() {
companion object {
@@ -98,4 +98,4 @@
assertNull(customIconCache.retrieve(TEST_COMPONENT1, CONTROL_ID_1))
}
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/AuxiliaryPersistenceWrapperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/AuxiliaryPersistenceWrapperTest.kt
index 129fe9a..8d6e3a0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/AuxiliaryPersistenceWrapperTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/AuxiliaryPersistenceWrapperTest.kt
@@ -17,7 +17,7 @@
package com.android.systemui.controls.controller
import android.content.ComponentName
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import org.junit.Assert.assertEquals
@@ -37,7 +37,7 @@
import java.io.File
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class AuxiliaryPersistenceWrapperTest : SysuiTestCase() {
companion object {
@@ -128,4 +128,4 @@
verify(persistenceWrapper, never()).storeFavorites(ArgumentMatchers.anyList())
}
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlActionCoordinatorImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlActionCoordinatorImplTest.kt
index 6cc3ef19..9285146 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlActionCoordinatorImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlActionCoordinatorImplTest.kt
@@ -16,8 +16,8 @@
package com.android.systemui.controls.ui
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
-import android.testing.AndroidTestingRunner
import android.view.HapticFeedbackConstants
import com.android.systemui.SysuiTestCase
import com.android.systemui.broadcast.BroadcastSender
@@ -48,7 +48,7 @@
import java.util.Optional
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class ControlActionCoordinatorImplTest : SysuiTestCase() {
@Mock
private lateinit var vibratorHelper: VibratorHelper
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsBindingControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsBindingControllerImplTest.kt
index 724c9d1..ed0c7ee 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsBindingControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsBindingControllerImplTest.kt
@@ -24,7 +24,7 @@
import android.service.controls.DeviceTypes
import android.service.controls.IControlsSubscriber
import android.service.controls.IControlsSubscription
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.settings.UserTracker
@@ -49,7 +49,7 @@
import org.mockito.MockitoAnnotations
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class ControlsBindingControllerImplTest : SysuiTestCase() {
companion object {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt
index de455f63..cf385e7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt
@@ -26,7 +26,7 @@
import android.service.controls.Control
import android.service.controls.DeviceTypes
import android.service.controls.actions.ControlAction
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.backup.BackupHelper
@@ -74,7 +74,7 @@
import java.util.function.Consumer
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class ControlsControllerImplTest : SysuiTestCase() {
private val kosmos = testKosmos()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsFavoritePersistenceWrapperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsFavoritePersistenceWrapperTest.kt
index 690b9a7..afa5cec 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsFavoritePersistenceWrapperTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsFavoritePersistenceWrapperTest.kt
@@ -18,7 +18,7 @@
import android.content.ComponentName
import android.service.controls.DeviceTypes
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.util.concurrency.FakeExecutor
@@ -32,7 +32,7 @@
import java.io.File
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class ControlsFavoritePersistenceWrapperTest : SysuiTestCase() {
private lateinit var file: File
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManagerTest.kt
index b5d3476..f9c2c6b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManagerTest.kt
@@ -26,7 +26,7 @@
import android.service.controls.IControlsSubscriber
import android.service.controls.actions.ControlAction
import android.service.controls.actions.ControlActionWrapper
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.util.concurrency.FakeExecutor
@@ -57,7 +57,7 @@
import org.mockito.MockitoAnnotations
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class ControlsProviderLifecycleManagerTest : SysuiTestCase() {
@Mock
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsTileResourceConfigurationImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsTileResourceConfigurationImplTest.kt
index 581e88b..e04ce45 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsTileResourceConfigurationImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsTileResourceConfigurationImplTest.kt
@@ -16,7 +16,7 @@
package com.android.systemui.controls.controller
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.res.R
import com.android.systemui.SysuiTestCase
@@ -25,7 +25,7 @@
import org.junit.Test
import org.junit.runner.RunWith
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
class ControlsTileResourceConfigurationImplTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/DeletionJobServiceTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/DeletionJobServiceTest.kt
index 2283746..b6ea62e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/DeletionJobServiceTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/DeletionJobServiceTest.kt
@@ -19,7 +19,7 @@
import android.app.job.JobParameters
import android.content.Context
import android.os.PersistableBundle
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.controls.controller.AuxiliaryPersistenceWrapper.DeletionJobService.Companion.USER
@@ -37,7 +37,7 @@
import org.mockito.MockitoAnnotations
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class DeletionJobServiceTest : SysuiTestCase() {
@Mock private lateinit var context: Context
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/PackageUpdateMonitorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/PackageUpdateMonitorTest.kt
index 85d6211..282ea5c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/PackageUpdateMonitorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/PackageUpdateMonitorTest.kt
@@ -20,7 +20,7 @@
import android.content.pm.PackageManager
import android.os.Handler
import android.os.UserHandle
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.util.mockito.any
@@ -39,7 +39,7 @@
import org.mockito.MockitoAnnotations
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class PackageUpdateMonitorTest : SysuiTestCase() {
@Mock private lateinit var context: Context
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ServiceWrapperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ServiceWrapperTest.kt
index 789d6df..b5c6c53 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ServiceWrapperTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ServiceWrapperTest.kt
@@ -23,7 +23,7 @@
import android.service.controls.IControlsSubscription
import android.service.controls.actions.ControlAction
import android.service.controls.actions.ControlActionWrapper
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import org.junit.Assert.assertEquals
@@ -42,7 +42,7 @@
import org.mockito.MockitoAnnotations
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class ServiceWrapperTest : SysuiTestCase() {
@Mock
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/StatefulControlSubscriberTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/StatefulControlSubscriberTest.kt
index 267520e..7d197f7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/StatefulControlSubscriberTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/StatefulControlSubscriberTest.kt
@@ -20,7 +20,7 @@
import android.os.Binder
import android.service.controls.Control
import android.service.controls.IControlsSubscription
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.util.concurrency.FakeExecutor
@@ -36,7 +36,7 @@
import org.mockito.MockitoAnnotations
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class StatefulControlSubscriberTest : SysuiTestCase() {
@Mock
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/dagger/ControlsComponentTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/dagger/ControlsComponentTest.kt
index 54f66dc..844cc1f1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/dagger/ControlsComponentTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/dagger/ControlsComponentTest.kt
@@ -16,7 +16,7 @@
package com.android.systemui.controls.dagger
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.internal.widget.LockPatternUtils
import com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED
@@ -45,7 +45,7 @@
import org.mockito.MockitoAnnotations
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class ControlsComponentTest : SysuiTestCase() {
@Mock private lateinit var controller: ControlsController
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/management/AllModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/management/AllModelTest.kt
index 4ea9616..5528f65 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/management/AllModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/management/AllModelTest.kt
@@ -19,7 +19,7 @@
import android.app.PendingIntent
import android.content.ComponentName
import android.service.controls.Control
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.controls.ControlStatus
@@ -37,7 +37,7 @@
import org.mockito.MockitoAnnotations
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class AllModelTest : SysuiTestCase() {
companion object {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/management/AppAdapterTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/management/AppAdapterTest.kt
index 226ef3b..56c7c85 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/management/AppAdapterTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/management/AppAdapterTest.kt
@@ -18,10 +18,10 @@
import android.content.ComponentName
import android.content.res.Resources
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.view.LayoutInflater
import android.view.View
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.settingslib.core.lifecycle.Lifecycle
import com.android.systemui.SysuiTestCase
@@ -45,7 +45,7 @@
import java.text.Collator
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
class AppAdapterTest : SysuiTestCase() {
private val fakeSystemClock = FakeSystemClock()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsEditingActivityTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsEditingActivityTest.kt
index 2a4524b..39e1e1d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsEditingActivityTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsEditingActivityTest.kt
@@ -3,12 +3,12 @@
import android.content.ComponentName
import android.content.Intent
import android.os.Bundle
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.view.View
import android.widget.Button
import android.window.OnBackInvokedCallback
import android.window.OnBackInvokedDispatcher
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import androidx.test.rule.ActivityTestRule
import com.android.systemui.res.R
@@ -33,7 +33,7 @@
import org.mockito.MockitoAnnotations
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@TestableLooper.RunWithLooper
class ControlsEditingActivityTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsFavoritingActivityTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsFavoritingActivityTest.kt
index 88d36af..f5616d4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsFavoritingActivityTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsFavoritingActivityTest.kt
@@ -4,12 +4,12 @@
import android.content.Intent
import android.os.Bundle
import android.service.controls.Control
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.view.View
import android.widget.Button
import android.window.OnBackInvokedCallback
import android.window.OnBackInvokedDispatcher
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.FlakyTest
import androidx.test.filters.SmallTest
import androidx.test.rule.ActivityTestRule
@@ -45,7 +45,7 @@
import org.mockito.MockitoAnnotations
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@TestableLooper.RunWithLooper
class ControlsFavoritingActivityTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsListingControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsListingControllerImplTest.kt
index 6361e94..e4f0910 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsListingControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsListingControllerImplTest.kt
@@ -28,7 +28,7 @@
import android.os.Bundle
import android.os.UserHandle
import android.service.controls.ControlsProviderService
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.settingslib.applications.ServiceListing
import com.android.systemui.res.R
@@ -65,7 +65,7 @@
import org.mockito.MockitoAnnotations
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class ControlsListingControllerImplTest : SysuiTestCase() {
companion object {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsProviderSelectorActivityTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsProviderSelectorActivityTest.kt
index d17495f..7698520 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsProviderSelectorActivityTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsProviderSelectorActivityTest.kt
@@ -23,10 +23,10 @@
import android.content.pm.ServiceInfo
import android.graphics.drawable.Drawable
import android.os.Bundle
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.window.OnBackInvokedCallback
import android.window.OnBackInvokedDispatcher
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import androidx.test.rule.ActivityTestRule
import com.android.systemui.SysuiTestCase
@@ -65,7 +65,7 @@
import org.mockito.MockitoAnnotations
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@TestableLooper.RunWithLooper
class ControlsProviderSelectorActivityTest : SysuiTestCase() {
@Main private val executor: Executor = MoreExecutors.directExecutor()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsRequestDialogTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsRequestDialogTest.kt
index ca970bb..5008927 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsRequestDialogTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsRequestDialogTest.kt
@@ -25,9 +25,9 @@
import android.service.controls.Control
import android.service.controls.ControlsProviderService
import android.service.controls.DeviceTypes
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import androidx.lifecycle.Lifecycle
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.MediumTest
import androidx.test.rule.ActivityTestRule
import com.android.systemui.SysuiTestCase
@@ -53,7 +53,7 @@
import java.util.concurrent.Executor
@MediumTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@TestableLooper.RunWithLooper
class ControlsRequestDialogTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsRequestReceiverTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsRequestReceiverTest.kt
index ae77d1f..c49867a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsRequestReceiverTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsRequestReceiverTest.kt
@@ -30,7 +30,7 @@
import android.os.UserHandle
import android.service.controls.Control
import android.service.controls.ControlsProviderService
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import org.junit.Assert.assertEquals
@@ -49,7 +49,7 @@
import org.mockito.MockitoAnnotations
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class ControlsRequestReceiverTest : SysuiTestCase() {
@Mock
@@ -266,4 +266,4 @@
}
}
}
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/management/FavoritesModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/management/FavoritesModelTest.kt
index f0003ed..281addc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/management/FavoritesModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/management/FavoritesModelTest.kt
@@ -17,8 +17,8 @@
package com.android.systemui.controls.management
import android.content.ComponentName
-import android.testing.AndroidTestingRunner
import androidx.recyclerview.widget.RecyclerView
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.controls.ControlInterface
@@ -43,7 +43,7 @@
import org.mockito.MockitoAnnotations
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class FavoritesModelTest : SysuiTestCase() {
companion object {
@@ -299,4 +299,4 @@
}
private fun getDividerPosition(): Int = model.elements.indexOf(dividerWrapper)
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/management/PanelConfirmationDialogFactoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/management/PanelConfirmationDialogFactoryTest.kt
index 7f0ea9a..d8aac10 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/management/PanelConfirmationDialogFactoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/management/PanelConfirmationDialogFactoryTest.kt
@@ -19,7 +19,7 @@
import android.content.Context
import android.content.DialogInterface
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.res.R
@@ -39,7 +39,7 @@
import org.mockito.Mockito.`when` as whenever
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class PanelConfirmationDialogFactoryTest : SysuiTestCase() {
@Mock private lateinit var mockDialog : SystemUIDialog
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/panels/AuthorizedPanelsRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/panels/AuthorizedPanelsRepositoryImplTest.kt
index 18ce4a8..fd4c681 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/panels/AuthorizedPanelsRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/panels/AuthorizedPanelsRepositoryImplTest.kt
@@ -19,7 +19,7 @@
import android.content.SharedPreferences
import android.content.pm.UserInfo
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
@@ -37,7 +37,7 @@
import org.junit.Test
import org.junit.runner.RunWith
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
class AuthorizedPanelsRepositoryImplTest : SysuiTestCase() {
val kosmos = testKosmos()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/panels/SelectedComponentRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/panels/SelectedComponentRepositoryTest.kt
index a7e7ba9..86e3481 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/panels/SelectedComponentRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/panels/SelectedComponentRepositoryTest.kt
@@ -19,7 +19,7 @@
import android.content.ComponentName
import android.content.SharedPreferences
import android.os.UserHandle
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
@@ -43,7 +43,7 @@
import org.mockito.MockitoAnnotations
@ExperimentalCoroutinesApi
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
class SelectedComponentRepositoryTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/settings/ControlsSettingsDialogManagerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/settings/ControlsSettingsDialogManagerImplTest.kt
index 154c373..aee334f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/settings/ControlsSettingsDialogManagerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/settings/ControlsSettingsDialogManagerImplTest.kt
@@ -22,8 +22,8 @@
import android.database.ContentObserver
import android.provider.Settings.Secure.LOCKSCREEN_ALLOW_TRIVIAL_CONTROLS
import android.provider.Settings.Secure.LOCKSCREEN_SHOW_CONTROLS
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.controls.settings.ControlsSettingsDialogManager.Companion.PREFS_SETTINGS_DIALOG_ATTEMPTS
@@ -52,7 +52,7 @@
import org.mockito.MockitoAnnotations
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@TestableLooper.RunWithLooper
class ControlsSettingsDialogManagerImplTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/settings/ControlsSettingsRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/settings/ControlsSettingsRepositoryImplTest.kt
index b904ac1..3bdd5cf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/settings/ControlsSettingsRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/settings/ControlsSettingsRepositoryImplTest.kt
@@ -19,6 +19,7 @@
import android.content.pm.UserInfo
import android.provider.Settings
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.user.data.repository.FakeUserRepository
@@ -33,10 +34,9 @@
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
@SmallTest
-@RunWith(JUnit4::class)
+@RunWith(AndroidJUnit4::class)
@OptIn(ExperimentalCoroutinesApi::class)
class ControlsSettingsRepositoryImplTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/start/ControlsStartableTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/start/ControlsStartableTest.kt
index c44429b..9e8914a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/start/ControlsStartableTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/start/ControlsStartableTest.kt
@@ -26,7 +26,7 @@
import android.content.pm.ServiceInfo
import android.os.UserHandle
import android.os.UserManager
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.broadcast.BroadcastDispatcher
@@ -75,7 +75,7 @@
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class ControlsStartableTest : SysuiTestCase() {
private val kosmos = testKosmos()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/CanUseIconPredicateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/CanUseIconPredicateTest.kt
index bfdb923..193ce21 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/CanUseIconPredicateTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/CanUseIconPredicateTest.kt
@@ -21,7 +21,7 @@
import android.graphics.drawable.Icon
import android.net.Uri
import android.os.UserHandle
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.google.common.truth.Truth.assertThat
@@ -29,7 +29,7 @@
import org.junit.runner.RunWith
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class CanUseIconPredicateTest : SysuiTestCase() {
private companion object {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlViewHolderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlViewHolderTest.kt
index 101b8ed..4b30fa5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlViewHolderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlViewHolderTest.kt
@@ -24,11 +24,11 @@
import android.service.controls.Control
import android.service.controls.DeviceTypes
import android.service.controls.templates.ControlTemplate
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.res.R
import com.android.systemui.SysuiTestCase
@@ -44,7 +44,7 @@
import org.mockito.Mockito.mock
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@TestableLooper.RunWithLooper
class ControlViewHolderTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsActivityTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsActivityTest.kt
index e279d28..03aa622 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsActivityTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsActivityTest.kt
@@ -19,8 +19,8 @@
import android.content.Intent
import android.content.res.Configuration
import android.service.dreams.IDreamManager
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import androidx.test.rule.ActivityTestRule
import com.android.systemui.SysuiTestCase
@@ -39,7 +39,7 @@
import org.mockito.MockitoAnnotations
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@TestableLooper.RunWithLooper
class ControlsActivityTest : SysuiTestCase() {
@Mock private lateinit var uiController: ControlsUiController
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsDialogsFactoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsDialogsFactoryTest.kt
index 38c6a0e..ca33f16 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsDialogsFactoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsDialogsFactoryTest.kt
@@ -18,7 +18,7 @@
package com.android.systemui.controls.ui
import android.content.Context
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.res.R
import com.android.systemui.SysuiTestCase
@@ -36,7 +36,7 @@
import org.mockito.MockitoAnnotations
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class ControlsDialogsFactoryTest : SysuiTestCase() {
private companion object {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsPopupMenuTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsPopupMenuTest.kt
index 48e3962..66303eb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsPopupMenuTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsPopupMenuTest.kt
@@ -19,12 +19,12 @@
import android.app.Activity
import android.graphics.Color
import android.graphics.drawable.ShapeDrawable
-import android.testing.AndroidTestingRunner
import android.util.DisplayMetrics
import android.view.View
import android.view.ViewGroup
import android.widget.PopupWindow.OnDismissListener
import androidx.test.ext.junit.rules.ActivityScenarioRule
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.res.R
import com.android.systemui.SysuiTestCase
@@ -43,7 +43,7 @@
import org.mockito.MockitoAnnotations
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
open class ControlsPopupMenuTest : SysuiTestCase() {
private companion object {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsUiControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsUiControllerImplTest.kt
index 8f3813d..20890a7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsUiControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsUiControllerImplTest.kt
@@ -26,13 +26,13 @@
import android.os.UserHandle
import android.service.controls.ControlsProviderService
import android.service.controls.flags.Flags.FLAG_HOME_PANEL_DREAM
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.util.AttributeSet
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.controls.ControlsMetricsLogger
@@ -83,7 +83,7 @@
import org.mockito.MockitoAnnotations
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@TestableLooper.RunWithLooper
class ControlsUiControllerImplTest : SysuiTestCase() {
private val kosmos = testKosmos()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/DetailDialogTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/DetailDialogTest.kt
index 677108c..10b3ce3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/DetailDialogTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/DetailDialogTest.kt
@@ -19,9 +19,9 @@
import android.app.ActivityOptions
import android.app.PendingIntent
import android.content.Context
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import androidx.test.ext.junit.rules.ActivityScenarioRule
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.activity.EmptyTestActivity
@@ -44,7 +44,7 @@
import org.mockito.MockitoAnnotations
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@TestableLooper.RunWithLooper
class DetailDialogTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/OverflowMenuAdapterTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/OverflowMenuAdapterTest.kt
index 483ab3b..6092b8c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/OverflowMenuAdapterTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/OverflowMenuAdapterTest.kt
@@ -17,7 +17,7 @@
package com.android.systemui.controls.ui
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.google.common.truth.Truth.assertThat
@@ -25,7 +25,7 @@
import org.junit.runner.RunWith
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class OverflowMenuAdapterTest : SysuiTestCase() {
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/PanelTaskViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/PanelTaskViewControllerTest.kt
index 021facc..de2d852 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/PanelTaskViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/PanelTaskViewControllerTest.kt
@@ -25,8 +25,8 @@
import android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK
import android.content.Intent.FLAG_ACTIVITY_NEW_TASK
import android.graphics.Rect
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.util.boundsOnScreen
@@ -49,7 +49,7 @@
import org.mockito.MockitoAnnotations
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@TestableLooper.RunWithLooper
class PanelTaskViewControllerTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/SelectionItemTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/SelectionItemTest.kt
index 57176f0..4579807 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/SelectionItemTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/SelectionItemTest.kt
@@ -1,7 +1,7 @@
package com.android.systemui.controls.ui
import android.content.ComponentName
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.controls.controller.StructureInfo
@@ -11,7 +11,7 @@
import org.junit.runner.RunWith
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class SelectionItemTest : SysuiTestCase() {
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ToggleRangeTemplateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ToggleRangeTemplateTest.kt
index 31e0954..9f4836a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ToggleRangeTemplateTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ToggleRangeTemplateTest.kt
@@ -17,7 +17,7 @@
package com.android.systemui.controls.ui
import android.service.controls.templates.RangeTemplate
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import org.junit.Assert.assertEquals
@@ -25,7 +25,7 @@
import org.junit.runner.RunWith
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class ToggleRangeTemplateTest : SysuiTestCase() {
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/coroutines/FlowTest.kt b/packages/SystemUI/tests/src/com/android/systemui/coroutines/FlowTest.kt
index 1e4753e..23da3f1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/coroutines/FlowTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/coroutines/FlowTest.kt
@@ -1,6 +1,6 @@
package com.android.systemui.coroutines
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.google.common.truth.Truth.assertThat
@@ -12,7 +12,7 @@
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class FlowTest : SysuiTestCase() {
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/decor/CutoutDecorProviderFactoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/decor/CutoutDecorProviderFactoryTest.kt
index 1040ec4..f029847 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/decor/CutoutDecorProviderFactoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/decor/CutoutDecorProviderFactoryTest.kt
@@ -18,7 +18,6 @@
import android.graphics.Insets
import android.graphics.Rect
-import android.testing.AndroidTestingRunner
import android.testing.TestableResources
import android.util.RotationUtils
import android.util.Size
@@ -27,6 +26,7 @@
import android.view.DisplayCutout.BOUNDS_POSITION_LENGTH
import android.view.DisplayInfo
import android.view.Surface
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.util.mockito.any
@@ -38,7 +38,7 @@
import org.mockito.Mockito.doAnswer
import org.mockito.MockitoAnnotations
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
class CutoutDecorProviderFactoryTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/decor/OverlayWindowTest.kt b/packages/SystemUI/tests/src/com/android/systemui/decor/OverlayWindowTest.kt
index a1cffc1..69fab56 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/decor/OverlayWindowTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/decor/OverlayWindowTest.kt
@@ -17,11 +17,11 @@
package com.android.systemui.decor
import android.graphics.Color
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
import android.view.DisplayCutout
import android.view.Surface
import android.view.View
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.res.R
import com.android.systemui.SysuiTestCase
@@ -34,7 +34,7 @@
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@RunWithLooper(setAsMainLooper = true)
@SmallTest
class OverlayWindowTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/decor/PrivacyDotDecorProviderFactoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/decor/PrivacyDotDecorProviderFactoryTest.kt
index e4ddc37..6d6c6ef 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/decor/PrivacyDotDecorProviderFactoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/decor/PrivacyDotDecorProviderFactoryTest.kt
@@ -17,8 +17,8 @@
package com.android.systemui.decor
import android.content.res.Resources
-import android.testing.AndroidTestingRunner
import android.view.DisplayCutout
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.res.R
import com.android.systemui.SysuiTestCase
@@ -30,7 +30,7 @@
import org.mockito.Mockito.spy
import org.mockito.Mockito.`when` as whenever
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
class PrivacyDotDecorProviderFactoryTest : SysuiTestCase() {
private lateinit var mPrivacyDotDecorProviderFactory: PrivacyDotDecorProviderFactory
@@ -83,4 +83,4 @@
and it.alignedBounds.contains(DisplayCutout.BOUNDS_POSITION_RIGHT))
})
}
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/decor/RoundedCornerDecorProviderFactoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/decor/RoundedCornerDecorProviderFactoryTest.kt
index d1d4880..4da988a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/decor/RoundedCornerDecorProviderFactoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/decor/RoundedCornerDecorProviderFactoryTest.kt
@@ -16,9 +16,9 @@
package com.android.systemui.decor
-import android.testing.AndroidTestingRunner
import android.util.Size
import android.view.DisplayCutout
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.res.R
import com.android.systemui.SysuiTestCase
@@ -30,7 +30,7 @@
import org.mockito.Mockito
import org.mockito.Mockito.spy
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
class RoundedCornerDecorProviderFactoryTest : SysuiTestCase() {
@@ -139,4 +139,4 @@
})
}
}
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/decor/RoundedCornerResDelegateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/decor/RoundedCornerResDelegateTest.kt
index 2bff7d2..9d440c3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/decor/RoundedCornerResDelegateTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/decor/RoundedCornerResDelegateTest.kt
@@ -18,9 +18,9 @@
import android.content.res.TypedArray
import android.graphics.drawable.Drawable
-import android.testing.AndroidTestingRunner
import android.util.Size
import androidx.annotation.DrawableRes
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.internal.R as InternalR
import com.android.systemui.res.R as SystemUIR
@@ -33,7 +33,7 @@
import org.mockito.Mock
import org.mockito.MockitoAnnotations
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
class RoundedCornerResDelegateTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/demomode/DemoModeControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/demomode/DemoModeControllerTest.kt
index 6c2e136..4793a52f3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/demomode/DemoModeControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/demomode/DemoModeControllerTest.kt
@@ -18,8 +18,8 @@
import android.content.Intent
import android.os.Bundle
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.demomode.DemoMode.ACTION_DEMO
@@ -40,7 +40,7 @@
@Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
@OptIn(ExperimentalCoroutinesApi::class)
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@TestableLooper.RunWithLooper
@SmallTest
class DemoModeControllerTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/deviceentry/data/repository/FaceWakeUpTriggersConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/deviceentry/data/repository/FaceWakeUpTriggersConfigTest.kt
index e9b4bbb..6b0de92 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/deviceentry/data/repository/FaceWakeUpTriggersConfigTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/deviceentry/data/repository/FaceWakeUpTriggersConfigTest.kt
@@ -17,7 +17,7 @@
package com.android.systemui.deviceentry.data.repository
import android.os.PowerManager
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.dump.DumpManager
@@ -30,7 +30,7 @@
import org.mockito.Mock
import org.mockito.MockitoAnnotations
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
class FaceWakeUpTriggersConfigTest : SysuiTestCase() {
@Mock lateinit var globalSettings: GlobalSettings
diff --git a/packages/SystemUI/tests/src/com/android/systemui/devicepolicy/DevicePolicyManagerExtTest.kt b/packages/SystemUI/tests/src/com/android/systemui/devicepolicy/DevicePolicyManagerExtTest.kt
index 8203291..64ff5f7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/devicepolicy/DevicePolicyManagerExtTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/devicepolicy/DevicePolicyManagerExtTest.kt
@@ -22,6 +22,7 @@
import android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_NONE
import android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA
import android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_SHORTCUTS_ALL
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.settings.UserTracker
@@ -31,13 +32,12 @@
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.Mock
import org.mockito.MockitoAnnotations
@SmallTest
-@RunWith(JUnit4::class)
+@RunWith(AndroidJUnit4::class)
class DevicePolicyManagerExtTest : SysuiTestCase() {
@Mock lateinit var devicePolicyManager: DevicePolicyManager
diff --git a/packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DeviceStateRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DeviceStateRepositoryTest.kt
index c79cbab..3f5b9a3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DeviceStateRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DeviceStateRepositoryTest.kt
@@ -17,8 +17,8 @@
package com.android.systemui.display.data.repository
import android.hardware.devicestate.DeviceStateManager
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.internal.R
import com.android.systemui.SysuiTestCase
@@ -41,7 +41,7 @@
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@TestableLooper.RunWithLooper
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
diff --git a/packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DisplayRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DisplayRepositoryTest.kt
index 68d49c7..01868ae 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DisplayRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DisplayRepositoryTest.kt
@@ -18,11 +18,11 @@
import android.hardware.display.DisplayManager
import android.os.Looper
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.view.Display
import android.view.Display.TYPE_EXTERNAL
import android.view.Display.TYPE_INTERNAL
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.FlowValue
@@ -46,7 +46,7 @@
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@TestableLooper.RunWithLooper
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
diff --git a/packages/SystemUI/tests/src/com/android/systemui/display/domain/interactor/ConnectedDisplayInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/display/domain/interactor/ConnectedDisplayInteractorTest.kt
index 37c7409..fd9964f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/display/domain/interactor/ConnectedDisplayInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/display/domain/interactor/ConnectedDisplayInteractorTest.kt
@@ -19,12 +19,12 @@
import android.companion.virtual.VirtualDeviceManager
import android.companion.virtual.flags.Flags.FLAG_INTERACTIVE_SCREEN_MIRROR
import android.platform.test.annotations.EnableFlags
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.view.Display
import android.view.Display.TYPE_EXTERNAL
import android.view.Display.TYPE_INTERNAL
import android.view.Display.TYPE_VIRTUAL
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.FlowValue
@@ -53,7 +53,7 @@
import org.junit.runner.RunWith
import org.mockito.Mockito.anyInt
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@TestableLooper.RunWithLooper
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
diff --git a/packages/SystemUI/tests/src/com/android/systemui/display/ui/view/MirroringConfirmationDialogDelegateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/display/ui/view/MirroringConfirmationDialogDelegateTest.kt
index d118cc7..8105bc8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/display/ui/view/MirroringConfirmationDialogDelegateTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/display/ui/view/MirroringConfirmationDialogDelegateTest.kt
@@ -18,13 +18,13 @@
import android.app.Dialog
import android.graphics.Insets
-import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.view.LayoutInflater
import android.view.View
import android.view.Window
import android.view.WindowInsets
import android.view.WindowInsetsAnimation
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.app.animation.Interpolators
import com.android.systemui.SysuiTestCase
@@ -42,7 +42,7 @@
import org.mockito.Mockito.verify
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
class MirroringConfirmationDialogDelegateTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeDockHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeDockHandlerTest.java
index 6d2df19..8c125f8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeDockHandlerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeDockHandlerTest.java
@@ -28,9 +28,9 @@
import android.app.ActivityManager;
import android.hardware.display.AmbientDisplayConfiguration;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper.RunWithLooper;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -46,7 +46,7 @@
import org.mockito.MockitoAnnotations;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@RunWithLooper
public class DozeDockHandlerTest extends SysuiTestCase {
@Mock private DozeMachine mMachine;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java
index 27fd3b1..aa5edae 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java
@@ -45,8 +45,8 @@
import android.os.PowerManager;
import android.os.UserHandle;
import android.provider.Settings;
-import android.testing.AndroidTestingRunner;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -71,7 +71,7 @@
import java.util.Optional;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
public class DozeScreenBrightnessTest extends SysuiTestCase {
private static final int DEFAULT_BRIGHTNESS = 10;
@@ -583,4 +583,4 @@
private void waitForSensorManager() {
mFakeExecutor.runAllReady();
}
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java
index 3cc0451..9c127b8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java
@@ -42,10 +42,10 @@
import android.database.ContentObserver;
import android.hardware.Sensor;
import android.hardware.display.AmbientDisplayConfiguration;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -75,7 +75,7 @@
import java.util.List;
import java.util.function.Consumer;
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@RunWithLooper
@SmallTest
public class DozeSensorsTest extends SysuiTestCase {
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 92941f9..fad52e0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSuppressorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSuppressorTest.java
@@ -38,9 +38,9 @@
import android.app.ActivityManager;
import android.hardware.display.AmbientDisplayConfiguration;
-import android.testing.AndroidTestingRunner;
import android.testing.UiThreadTest;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -60,7 +60,7 @@
import org.mockito.MockitoAnnotations;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@UiThreadTest
public class DozeSuppressorTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
index 40b8fc7..3d1a0d0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
@@ -38,10 +38,10 @@
import android.hardware.Sensor;
import android.hardware.display.AmbientDisplayConfiguration;
import android.platform.test.annotations.EnableFlags;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper.RunWithLooper;
import android.view.Display;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.internal.logging.InstanceId;
@@ -80,7 +80,7 @@
import org.mockito.MockitoAnnotations;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@RunWithLooper(setAsMainLooper = true)
public class DozeTriggersTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeWallpaperStateTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeWallpaperStateTest.java
index f07edf3..4253c76 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeWallpaperStateTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeWallpaperStateTest.java
@@ -26,6 +26,7 @@
import android.app.IWallpaperManager;
import android.os.RemoteException;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -36,11 +37,10 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-@RunWith(JUnit4.class)
+@RunWith(AndroidJUnit4.class)
@SmallTest
public class DozeWallpaperStateTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/FakeFeatureFlagsTest.kt b/packages/SystemUI/tests/src/com/android/systemui/flags/FakeFeatureFlagsTest.kt
index 2bd2bff..771ecaf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/flags/FakeFeatureFlagsTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/flags/FakeFeatureFlagsTest.kt
@@ -16,7 +16,7 @@
package com.android.systemui.flags
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.google.common.truth.Truth.assertThat
@@ -25,7 +25,7 @@
import org.junit.runner.RunWith
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class FakeFeatureFlagsTest : SysuiTestCase() {
private val unreleasedFlag = UnreleasedFlag("-1000", "test")
diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/FlagDependenciesTest.kt b/packages/SystemUI/tests/src/com/android/systemui/flags/FlagDependenciesTest.kt
index 91da88e..0ae59bb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/flags/FlagDependenciesTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/flags/FlagDependenciesTest.kt
@@ -16,8 +16,8 @@
package com.android.systemui.flags
-import android.testing.AndroidTestingRunner
import android.util.Log
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import java.io.PrintWriter
@@ -25,7 +25,7 @@
import org.junit.Test
import org.junit.runner.RunWith
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
@SmallTest
class FlagDependenciesTest : SysuiTestCase() {
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/ServerFlagReaderImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/flags/ServerFlagReaderImplTest.kt
index 2daa86b..d1082bd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/flags/ServerFlagReaderImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/flags/ServerFlagReaderImplTest.kt
@@ -16,7 +16,7 @@
package com.android.systemui.flags
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.util.DeviceConfigProxyFake
@@ -33,7 +33,7 @@
import org.mockito.MockitoAnnotations
@SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
class ServerFlagReaderImplTest : SysuiTestCase() {
private val NAMESPACE = "test"
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractorTest.kt
index 7c92ede..42ab25f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractorTest.kt
@@ -48,6 +48,7 @@
import com.android.systemui.kosmos.testScope
import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAsleepForTest
import com.android.systemui.power.domain.interactor.powerInteractor
+import com.android.systemui.statusbar.domain.interactor.keyguardOcclusionInteractor
import com.android.systemui.testKosmos
import kotlin.test.Test
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -78,6 +79,9 @@
fun setup() {
underTest.start()
+ kosmos.fakeKeyguardRepository.setDreaming(true)
+ kosmos.keyguardOcclusionInteractor.setWmNotifiedShowWhenLockedActivityOnTop(true)
+
// Transition to DOZING and set the power interactor asleep.
powerInteractor.setAsleepForTest()
runBlocking {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractorTest.kt
index 88fe4ce..af76b08 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractorTest.kt
@@ -16,12 +16,18 @@
package com.android.systemui.keyguard.domain.interactor
+import android.platform.test.annotations.DisableFlags
+import android.platform.test.annotations.EnableFlags
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
+import com.android.internal.widget.LockPatternUtils
+import com.android.systemui.Flags
import com.android.systemui.SysuiTestCase
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.data.repository.fakeBiometricSettingsRepository
import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.shared.model.AuthenticationFlags
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionStep
@@ -81,6 +87,7 @@
}
@Test
+ @DisableFlags(Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR)
fun testTransitionsToLockscreen_ifFinishedInGone() =
testScope.runTest {
keyguardTransitionRepository.sendTransitionSteps(
@@ -92,7 +99,34 @@
kosmos.fakeKeyguardRepository.setKeyguardShowing(true)
runCurrent()
- // We're in the middle of a LOCKSCREEN -> GONE transition.
+ // We're in the middle of a GONE -> LOCKSCREEN transition.
+ assertThat(keyguardTransitionRepository)
+ .startedTransition(
+ to = KeyguardState.LOCKSCREEN,
+ )
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR)
+ fun testTransitionsToLockscreen_ifFinishedInGone_wmRefactor() =
+ testScope.runTest {
+ keyguardTransitionRepository.sendTransitionSteps(
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.GONE,
+ testScope,
+ )
+ reset(keyguardTransitionRepository)
+
+ // Trigger lockdown.
+ kosmos.fakeBiometricSettingsRepository.setAuthenticationFlags(
+ AuthenticationFlags(
+ 0,
+ LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN
+ )
+ )
+ runCurrent()
+
+ // We're in the middle of a GONE -> LOCKSCREEN transition.
assertThat(keyguardTransitionRepository)
.startedTransition(
to = KeyguardState.LOCKSCREEN,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/InWindowLauncherUnlockAnimationInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/InWindowLauncherUnlockAnimationInteractorTest.kt
index c782e9d..459e41d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/InWindowLauncherUnlockAnimationInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/InWindowLauncherUnlockAnimationInteractorTest.kt
@@ -32,6 +32,7 @@
import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.keyguard.util.mockTopActivityClassName
import com.android.systemui.shared.system.ActivityManagerWrapper
+import com.android.systemui.user.domain.UserDomainLayerModule
import dagger.BindsInstance
import dagger.Component
import junit.framework.Assert.assertEquals
@@ -443,6 +444,7 @@
[
SysUITestModule::class,
BiometricsDomainLayerModule::class,
+ UserDomainLayerModule::class,
]
)
interface TestComponent {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/InWindowLauncherUnlockAnimationManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/InWindowLauncherUnlockAnimationManagerTest.kt
index 33e9b36..c7f4416 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/InWindowLauncherUnlockAnimationManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/InWindowLauncherUnlockAnimationManagerTest.kt
@@ -24,6 +24,7 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.ui.view.InWindowLauncherUnlockAnimationManager
import com.android.systemui.shared.system.smartspace.ILauncherUnlockAnimationController
+import com.android.systemui.user.domain.UserDomainLayerModule
import com.android.systemui.util.mockito.any
import dagger.BindsInstance
import dagger.Component
@@ -120,6 +121,7 @@
[
SysUITestModule::class,
BiometricsDomainLayerModule::class,
+ UserDomainLayerModule::class,
]
)
interface TestComponent {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/WindowManagerLockscreenVisibilityManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/WindowManagerLockscreenVisibilityManagerTest.kt
index 1f13298..4e1b12f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/WindowManagerLockscreenVisibilityManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/WindowManagerLockscreenVisibilityManagerTest.kt
@@ -100,9 +100,11 @@
}
@Test
- fun testAodVisible_noLockscreenShownCallYet_defaultsToShowLockscreen() {
+ fun testAodVisible_noLockscreenShownCallYet_doesNotShowLockscreenUntilLater() {
underTest.setAodVisible(false)
+ verifyNoMoreInteractions(activityTaskManagerService)
+ underTest.setLockscreenShown(true)
verify(activityTaskManagerService).setLockScreenShown(true, false)
verifyNoMoreInteractions(activityTaskManagerService)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDataFilterImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDataFilterImplTest.kt
index 8471fe1..064cf09 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDataFilterImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDataFilterImplTest.kt
@@ -663,6 +663,7 @@
true
)
mediaDataFilter.onMediaDataLoaded(KEY, null, dataCurrent)
+ repository.setOrderedMedia()
assertThat(currentMedia).containsExactly(controlCommonModel)
verify(listener)
@@ -706,6 +707,7 @@
true
)
mediaDataFilter.onMediaDataLoaded(KEY, null, dataCurrent)
+ repository.setOrderedMedia()
assertThat(currentMedia).containsExactly(controlCommonModel)
verify(listener)
.onMediaDataLoaded(eq(KEY), eq(null), eq(dataCurrent), eq(true), eq(0), eq(false))
@@ -760,6 +762,7 @@
)
mediaDataFilter.onMediaDataLoaded(KEY, null, dataCurrent)
+ repository.setOrderedMedia()
assertThat(currentMedia).containsExactly(controlCommonModel)
verify(listener)
@@ -834,6 +837,7 @@
)
val dataCurrent = dataMain.copy(active = false, lastActive = clock.elapsedRealtime())
mediaDataFilter.onMediaDataLoaded(KEY, null, dataCurrent)
+ repository.setOrderedMedia()
assertThat(currentMedia).containsExactly(controlCommonModel)
verify(listener)
@@ -922,6 +926,7 @@
// If there is media that was recently played but inactive
val dataCurrent = dataMain.copy(active = false, lastActive = clock.elapsedRealtime())
mediaDataFilter.onMediaDataLoaded(KEY, null, dataCurrent)
+ repository.setOrderedMedia()
verify(listener)
.onMediaDataLoaded(eq(KEY), eq(null), eq(dataCurrent), eq(true), eq(0), eq(false))
@@ -986,6 +991,7 @@
// WHEN we have media that was recently played, but not currently active
val dataCurrent = dataMain.copy(active = false, lastActive = clock.elapsedRealtime())
mediaDataFilter.onMediaDataLoaded(KEY, null, dataCurrent)
+ repository.setOrderedMedia()
verify(listener)
.onMediaDataLoaded(eq(KEY), eq(null), eq(dataCurrent), eq(true), eq(0), eq(false))
@@ -1039,6 +1045,7 @@
// WHEN we have media that was recently played, but not currently active
val dataCurrent = dataMain.copy(active = false, lastActive = clock.elapsedRealtime())
mediaDataFilter.onMediaDataLoaded(KEY, null, dataCurrent)
+ repository.setOrderedMedia()
verify(listener)
.onMediaDataLoaded(eq(KEY), eq(null), eq(dataCurrent), eq(true), eq(0), eq(false))
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDataProcessorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDataProcessorTest.kt
index 18b4c48..3b541cd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDataProcessorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDataProcessorTest.kt
@@ -242,7 +242,6 @@
mediaCarouselInteractor =
MediaCarouselInteractor(
applicationScope = testScope.backgroundScope,
- mediaDataRepository = mediaDataRepository,
mediaDataProcessor = mediaDataProcessor,
mediaTimeoutListener = mediaTimeoutListener,
mediaResumeListener = mediaResumeListener,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDeviceManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDeviceManagerTest.kt
index 42bd46f..5142730 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDeviceManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDeviceManagerTest.kt
@@ -21,6 +21,7 @@
import android.content.pm.ApplicationInfo
import android.content.pm.PackageManager
import android.graphics.drawable.Drawable
+import android.graphics.drawable.TestStubDrawable
import android.media.MediaRoute2Info
import android.media.MediaRouter2Manager
import android.media.RoutingSessionInfo
@@ -30,6 +31,7 @@
import android.platform.test.annotations.DisableFlags
import android.platform.test.annotations.EnableFlags
import android.platform.test.annotations.RequiresFlagsDisabled
+import android.platform.test.annotations.RequiresFlagsEnabled
import android.platform.test.flag.junit.DeviceFlagsValueProvider
import android.testing.TestableLooper
import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -89,6 +91,11 @@
@RunWith(AndroidJUnit4::class)
@TestableLooper.RunWithLooper
public class MediaDeviceManagerTest : SysuiTestCase() {
+
+ private companion object {
+ val OTHER_DEVICE_ICON_STUB = TestStubDrawable()
+ }
+
@get:Rule val checkFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule()
private lateinit var manager: MediaDeviceManager
@@ -155,6 +162,11 @@
MediaTestUtils.emptyMediaData.copy(packageName = PACKAGE, token = session.sessionToken)
whenever(controllerFactory.create(session.sessionToken)).thenReturn(controller)
setupLeAudioConfiguration(false)
+
+ context.orCreateTestableResources.addOverride(
+ R.drawable.ic_media_home_devices,
+ OTHER_DEVICE_ICON_STUB
+ )
}
@After
@@ -414,6 +426,7 @@
assertThat(data.name).isEqualTo(REMOTE_DEVICE_NAME)
}
+ @RequiresFlagsDisabled(FLAG_USE_PLAYBACK_INFO_FOR_ROUTING_CONTROLS)
@Test
fun onMediaDataLoaded_withRemotePlaybackInfo_noMatchingRoutingSession_setsDisabledDevice() {
// GIVEN that MR2Manager returns null for routing session
@@ -429,6 +442,24 @@
assertThat(data.name).isNull()
}
+ @RequiresFlagsEnabled(FLAG_USE_PLAYBACK_INFO_FOR_ROUTING_CONTROLS)
+ @Test
+ fun onMediaDataLoaded_withRemotePlaybackInfo_noMatchingRoutingSession_returnsOtherDevice() {
+ // GIVEN that MR2Manager returns null for routing session
+ whenever(playbackInfo.playbackType).thenReturn(PlaybackInfo.PLAYBACK_TYPE_REMOTE)
+ whenever(mr2.getRoutingSessionForMediaController(any())).thenReturn(null)
+ // WHEN a notification is added
+ manager.onMediaDataLoaded(KEY, null, mediaData)
+ fakeBgExecutor.runAllReady()
+ fakeFgExecutor.runAllReady()
+ // THEN the device is disabled and name and icon are set to "OTHER DEVICE".
+ val data = captureDeviceData(KEY)
+ assertThat(data.enabled).isFalse()
+ assertThat(data.name).isEqualTo(context.getString(R.string.media_seamless_other_device))
+ assertThat(data.icon).isEqualTo(OTHER_DEVICE_ICON_STUB)
+ }
+
+ @RequiresFlagsDisabled(FLAG_USE_PLAYBACK_INFO_FOR_ROUTING_CONTROLS)
@Test
fun onSelectedDeviceStateChanged_withRemotePlaybackInfo_noMatchingRoutingSession_setsDisabledDevice() {
// GIVEN a notif is added
@@ -449,7 +480,30 @@
assertThat(data.enabled).isFalse()
assertThat(data.name).isNull()
}
+ @RequiresFlagsEnabled(FLAG_USE_PLAYBACK_INFO_FOR_ROUTING_CONTROLS)
+ @Test
+ fun onSelectedDeviceStateChanged_withRemotePlaybackInfo_noMatchingRoutingSession_returnOtherDevice() {
+ // GIVEN a notif is added
+ manager.onMediaDataLoaded(KEY, null, mediaData)
+ fakeBgExecutor.runAllReady()
+ fakeFgExecutor.runAllReady()
+ reset(listener)
+ // AND MR2Manager returns null for routing session
+ whenever(playbackInfo.playbackType).thenReturn(PlaybackInfo.PLAYBACK_TYPE_REMOTE)
+ whenever(mr2.getRoutingSessionForMediaController(any())).thenReturn(null)
+ // WHEN the selected device changes state
+ val deviceCallback = captureCallback()
+ deviceCallback.onSelectedDeviceStateChanged(device, 1)
+ fakeBgExecutor.runAllReady()
+ fakeFgExecutor.runAllReady()
+ // THEN the device is disabled and name and icon are set to "OTHER DEVICE".
+ val data = captureDeviceData(KEY)
+ assertThat(data.enabled).isFalse()
+ assertThat(data.name).isEqualTo(context.getString(R.string.media_seamless_other_device))
+ assertThat(data.icon).isEqualTo(OTHER_DEVICE_ICON_STUB)
+ }
+ @RequiresFlagsDisabled(FLAG_USE_PLAYBACK_INFO_FOR_ROUTING_CONTROLS)
@Test
fun onDeviceListUpdate_withRemotePlaybackInfo_noMatchingRoutingSession_setsDisabledDevice() {
// GIVEN a notif is added
@@ -471,6 +525,29 @@
assertThat(data.name).isNull()
}
+ @RequiresFlagsEnabled(FLAG_USE_PLAYBACK_INFO_FOR_ROUTING_CONTROLS)
+ @Test
+ fun onDeviceListUpdate_withRemotePlaybackInfo_noMatchingRoutingSession_returnsOtherDevice() {
+ // GIVEN a notif is added
+ manager.onMediaDataLoaded(KEY, null, mediaData)
+ fakeBgExecutor.runAllReady()
+ fakeFgExecutor.runAllReady()
+ reset(listener)
+ // GIVEN that MR2Manager returns null for routing session
+ whenever(playbackInfo.playbackType).thenReturn(PlaybackInfo.PLAYBACK_TYPE_REMOTE)
+ whenever(mr2.getRoutingSessionForMediaController(any())).thenReturn(null)
+ // WHEN the selected device changes state
+ val deviceCallback = captureCallback()
+ deviceCallback.onDeviceListUpdate(mutableListOf(device))
+ fakeBgExecutor.runAllReady()
+ fakeFgExecutor.runAllReady()
+ // THEN device is disabled and name and icon are set to "OTHER DEVICE".
+ val data = captureDeviceData(KEY)
+ assertThat(data.enabled).isFalse()
+ assertThat(data.name).isEqualTo(context.getString(R.string.media_seamless_other_device))
+ assertThat(data.icon).isEqualTo(OTHER_DEVICE_ICON_STUB)
+ }
+
// With the flag enabled, MediaDeviceManager no longer gathers device name information directly.
@RequiresFlagsDisabled(FLAG_USE_PLAYBACK_INFO_FOR_ROUTING_CONTROLS)
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaCarouselControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaCarouselControllerTest.kt
index 6a2637d..ccf926a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaCarouselControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaCarouselControllerTest.kt
@@ -193,11 +193,12 @@
whenever(panel.mediaViewController).thenReturn(mediaViewController)
whenever(mediaFlags.isPersistentSsCardEnabled()).thenReturn(false)
MediaPlayerData.clear()
+ FakeExecutor.exhaustExecutors(bgExecutor)
verify(globalSettings)
- .registerContentObserverSync(
- eq(Settings.Global.getUriFor(Settings.Global.ANIMATOR_DURATION_SCALE)),
- capture(settingsObserverCaptor)
- )
+ .registerContentObserverSync(
+ eq(Settings.Global.getUriFor(Settings.Global.ANIMATOR_DURATION_SCALE)),
+ capture(settingsObserverCaptor)
+ )
}
@After
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/muteawait/MediaMuteAwaitConnectionManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/muteawait/MediaMuteAwaitConnectionManagerTest.kt
index 53e9dc8..2a8967e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/muteawait/MediaMuteAwaitConnectionManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/muteawait/MediaMuteAwaitConnectionManagerTest.kt
@@ -62,7 +62,7 @@
MockitoAnnotations.initMocks(this)
context.addMockSystemService(Context.AUDIO_SERVICE, audioManager)
icon = context.getDrawable(R.drawable.ic_cake)!!
- whenever(deviceIconUtil.getIconFromAudioDeviceType(any(), any())).thenReturn(icon)
+ whenever(deviceIconUtil.getIconFromAudioDeviceType(any())).thenReturn(icon)
muteAwaitConnectionManager = MediaMuteAwaitConnectionManager(
FakeExecutor(FakeSystemClock()),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileViewImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileViewImplTest.kt
index 130aafb..415cc7c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileViewImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileViewImplTest.kt
@@ -28,11 +28,12 @@
import android.widget.TextView
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
-import com.android.systemui.res.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.haptics.qs.QSLongPressEffect
import com.android.systemui.haptics.qs.qsLongPressEffect
import com.android.systemui.plugins.qs.QSTile
+import com.android.systemui.qs.qsTileFactory
+import com.android.systemui.res.R
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import org.junit.Before
@@ -46,8 +47,7 @@
@TestableLooper.RunWithLooper(setAsMainLooper = true)
class QSTileViewImplTest : SysuiTestCase() {
- @Mock
- private lateinit var customDrawable: Drawable
+ @Mock private lateinit var customDrawable: Drawable
private lateinit var tileView: FakeTileView
private lateinit var customDrawableView: View
@@ -130,9 +130,8 @@
tileView.changeState(state)
- assertThat(state.secondaryLabel as CharSequence).isEqualTo(
- context.getString(R.string.tile_unavailable)
- )
+ assertThat(state.secondaryLabel as CharSequence)
+ .isEqualTo(context.getString(R.string.tile_unavailable))
}
@Test
@@ -143,9 +142,8 @@
tileView.changeState(state)
- assertThat(state.secondaryLabel as CharSequence).isEqualTo(
- context.getString(R.string.switch_bar_off)
- )
+ assertThat(state.secondaryLabel as CharSequence)
+ .isEqualTo(context.getString(R.string.switch_bar_off))
}
@Test
@@ -156,9 +154,8 @@
tileView.changeState(state)
- assertThat(state.secondaryLabel as CharSequence).isEqualTo(
- context.getString(R.string.switch_bar_on)
- )
+ assertThat(state.secondaryLabel as CharSequence)
+ .isEqualTo(context.getString(R.string.switch_bar_on))
}
@Test
@@ -236,11 +233,10 @@
val offString = "${spec}_off"
val onString = "${spec}_on"
- context.orCreateTestableResources.addOverride(R.array.tile_states_internet, arrayOf(
- unavailableString,
- offString,
- onString
- ))
+ context.orCreateTestableResources.addOverride(
+ R.array.tile_states_internet,
+ arrayOf(unavailableString, offString, onString)
+ )
// State UNAVAILABLE
state.secondaryLabel = ""
@@ -342,11 +338,10 @@
@Test
fun testDisabledByPolicy_secondaryLabelText() {
val testA11yLabel = "TEST_LABEL"
- context.orCreateTestableResources
- .addOverride(
- R.string.accessibility_tile_disabled_by_policy_action_description,
- testA11yLabel
- )
+ context.orCreateTestableResources.addOverride(
+ R.string.accessibility_tile_disabled_by_policy_action_description,
+ testA11yLabel
+ )
val stateDisabledByPolicy = QSTile.State()
stateDisabledByPolicy.state = Tile.STATE_INACTIVE
@@ -357,10 +352,11 @@
val info = AccessibilityNodeInfo(tileView)
tileView.onInitializeAccessibilityNodeInfo(info)
assertThat(
- info.actionList.find {
- it.id == AccessibilityNodeInfo.AccessibilityAction.ACTION_CLICK.id
- }?.label
- ).isEqualTo(testA11yLabel)
+ info.actionList
+ .find { it.id == AccessibilityNodeInfo.AccessibilityAction.ACTION_CLICK.id }
+ ?.label
+ )
+ .isEqualTo(testA11yLabel)
}
@Test
@@ -375,11 +371,10 @@
val offString = "${spec}_off"
val onString = "${spec}_on"
- context.orCreateTestableResources.addOverride(R.array.tile_states_internet, arrayOf(
- unavailableString,
- offString,
- onString
- ))
+ context.orCreateTestableResources.addOverride(
+ R.array.tile_states_internet,
+ arrayOf(unavailableString, offString, onString)
+ )
tileView.changeState(state)
assertThat(tileView.stateDescription?.contains(unavailableString)).isTrue()
@@ -412,7 +407,7 @@
}
@Test
- fun onStateChange_fromLongPress_to_noLongPress_unBoundsTile() {
+ fun onStateChange_fromLongPress_to_noLongPress_clearsResources() {
// GIVEN a state that no longer handles long-press
val state = QSTile.State()
state.handlesLongClick = false
@@ -420,12 +415,12 @@
// WHEN the state changes
tileView.changeState(state)
- // THEN the view binder no longer binds the view to the long-press effect
- assertThat(tileView.isLongPressEffectBound).isFalse()
+ // THEN the long-press effect resources are not set
+ assertThat(tileView.areLongPressEffectPropertiesSet).isFalse()
}
@Test
- fun onStateChange_fromNoLongPress_to_longPress_bindsTile() {
+ fun onStateChange_fromNoLongPress_to_longPress_setsProperties() {
// GIVEN that the tile has changed to a state that does not handle long-press
val state = QSTile.State()
state.handlesLongClick = false
@@ -435,12 +430,12 @@
state.handlesLongClick = true
tileView.changeState(state)
- // THEN the view is bounded to the long-press effect
- assertThat(tileView.isLongPressEffectBound).isTrue()
+ // THEN the long-press effect resources are set
+ assertThat(tileView.areLongPressEffectPropertiesSet).isTrue()
}
@Test
- fun onStateChange_withoutLongPressEffect_fromLongPress_to_noLongPress_neverBindsEffect() {
+ fun onStateChange_withoutLongPressEffect_fromLongPress_to_noLongPress_neverSetsProperties() {
// GIVEN a tile where the long-press effect is null
tileView = FakeTileView(context, false, null)
@@ -451,13 +446,13 @@
// WHEN the state changes
tileView.changeState(state)
- // THEN the view binder does not bind the view and no effect is initialized
- assertThat(tileView.isLongPressEffectBound).isFalse()
+ // THEN the effect properties are not set and the effect is not initialized
+ assertThat(tileView.areLongPressEffectPropertiesSet).isFalse()
assertThat(tileView.isLongPressEffectInitialized).isFalse()
}
@Test
- fun onStateChange_withoutLongPressEffect_fromNoLongPress_to_longPress_neverBindsEffect() {
+ fun onStateChange_withoutLongPressEffect_fromNoLongPress_to_longPress_neverSetsProperties() {
// GIVEN a tile where the long-press effect is null
tileView = FakeTileView(context, false, null)
@@ -470,8 +465,8 @@
state.handlesLongClick = true
tileView.changeState(state)
- // THEN the view binder does not bind the view and no effect is initialized
- assertThat(tileView.isLongPressEffectBound).isFalse()
+ // THEN the effect properties are not set and the effect is not initialized
+ assertThat(tileView.areLongPressEffectPropertiesSet).isFalse()
assertThat(tileView.isLongPressEffectInitialized).isFalse()
}
@@ -490,14 +485,15 @@
// THE animation padding corresponds to the tile's growth due to the effect
val padding = tileView.getPaddingForLaunchAnimation()
- assertThat(padding).isEqualTo(
- Rect(
- -deltaWidth.toInt() / 2,
- -deltaHeight.toInt() / 2,
- deltaWidth.toInt() / 2,
- deltaHeight.toInt() / 2,
+ assertThat(padding)
+ .isEqualTo(
+ Rect(
+ -deltaWidth.toInt() / 2,
+ -deltaHeight.toInt() / 2,
+ deltaWidth.toInt() / 2,
+ deltaHeight.toInt() / 2,
+ )
)
- )
}
@Test
@@ -536,18 +532,44 @@
assertThat(tileView.haveLongPressPropertiesBeenReset).isTrue()
}
+ @Test
+ fun onInit_withLongPressEffect_longPressEffectHasTileAndExpandable() {
+ val tile = kosmos.qsTileFactory.createTile("Test Tile")
+ tileView.init(tile)
+
+ assertThat(tileView.isTileAddedToLongPress).isTrue()
+ assertThat(tileView.isExpandableAddedToLongPress).isTrue()
+ }
+
+ @Test
+ fun onInit_withoutLongPressEffect_longPressEffectDoesNotHaveTileAndExpandable() {
+ tileView = FakeTileView(context, false, null)
+ val tile = kosmos.qsTileFactory.createTile("Test Tile")
+ tileView.init(tile)
+
+ assertThat(tileView.isTileAddedToLongPress).isFalse()
+ assertThat(tileView.isExpandableAddedToLongPress).isFalse()
+ }
+
class FakeTileView(
context: Context,
collapsed: Boolean,
- longPressEffect: QSLongPressEffect?,
- ) : QSTileViewImpl(
+ private val longPressEffect: QSLongPressEffect?,
+ ) :
+ QSTileViewImpl(
ContextThemeWrapper(context, R.style.Theme_SystemUI_QuickSettings),
collapsed,
longPressEffect,
- ) {
+ ) {
var constantLongPressEffectDuration = 500
+ val isTileAddedToLongPress: Boolean
+ get() = longPressEffect?.qsTile != null
+
+ val isExpandableAddedToLongPress: Boolean
+ get() = longPressEffect?.expandable != null
override fun getLongPressEffectDuration(): Int = constantLongPressEffectDuration
+
fun changeState(state: QSTile.State) {
handleStateChanged(state)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.kt b/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.kt
index fc74586..6e6e311 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.kt
@@ -241,7 +241,6 @@
statusBarWinController,
sysUiState,
mock(),
- mock(),
userTracker,
wakefulnessLifecycle,
uiEventLogger,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt
index 068e166..066ca1c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt
@@ -762,6 +762,7 @@
// THEN the existing session is reused and views are registered
verify(smartspaceManager, never()).createSmartspaceSession(any())
verify(smartspaceView2).setUiSurface(BcSmartspaceDataPlugin.UI_SURFACE_LOCK_SCREEN_AOD)
+ verify(smartspaceView2).setTimeChangedDelegate(any())
verify(smartspaceView2).registerDataProvider(plugin)
verify(smartspaceView2).registerConfigProvider(configPlugin)
}
@@ -836,6 +837,7 @@
verify(dateSmartspaceView).setUiSurface(
BcSmartspaceDataPlugin.UI_SURFACE_LOCK_SCREEN_AOD)
+ verify(dateSmartspaceView).setTimeChangedDelegate(any())
verify(dateSmartspaceView).registerDataProvider(datePlugin)
verify(dateSmartspaceView).setPrimaryTextColor(anyInt())
@@ -848,6 +850,7 @@
verify(weatherSmartspaceView).setUiSurface(
BcSmartspaceDataPlugin.UI_SURFACE_LOCK_SCREEN_AOD)
+ verify(weatherSmartspaceView).setTimeChangedDelegate(any())
verify(weatherSmartspaceView).registerDataProvider(weatherPlugin)
verify(weatherSmartspaceView).setPrimaryTextColor(anyInt())
@@ -859,6 +862,7 @@
controller.stateChangeListener.onViewAttachedToWindow(view)
verify(smartspaceView).setUiSurface(BcSmartspaceDataPlugin.UI_SURFACE_LOCK_SCREEN_AOD)
+ verify(smartspaceView).setTimeChangedDelegate(any())
verify(smartspaceView).registerDataProvider(plugin)
verify(smartspaceView).registerConfigProvider(configPlugin)
verify(smartspaceSession)
@@ -984,6 +988,10 @@
override fun setUiSurface(uiSurface: String) {
}
+ override fun setTimeChangedDelegate(
+ delegate: BcSmartspaceDataPlugin.TimeChangedDelegate?
+ ) {}
+
override fun setDozeAmount(amount: Float) {
}
@@ -1012,6 +1020,10 @@
override fun setUiSurface(uiSurface: String) {
}
+ override fun setTimeChangedDelegate(
+ delegate: BcSmartspaceDataPlugin.TimeChangedDelegate?
+ ) {}
+
override fun setDozeAmount(amount: Float) {
}
@@ -1036,6 +1048,10 @@
override fun setUiSurface(uiSurface: String) {
}
+ override fun setTimeChangedDelegate(
+ delegate: BcSmartspaceDataPlugin.TimeChangedDelegate?
+ ) {}
+
override fun setDozeAmount(amount: Float) {
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/domain/interactor/NotificationIconsInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/domain/interactor/NotificationIconsInteractorTest.kt
index c9f2add..26f5370 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/domain/interactor/NotificationIconsInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/domain/interactor/NotificationIconsInteractorTest.kt
@@ -39,6 +39,7 @@
import com.android.systemui.statusbar.notification.shared.byIsSilent
import com.android.systemui.statusbar.notification.shared.byIsSuppressedFromStatusBar
import com.android.systemui.statusbar.notification.shared.byKey
+import com.android.systemui.user.domain.UserDomainLayerModule
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
@@ -156,7 +157,14 @@
private val bubbles: Bubbles = mock()
- @Component(modules = [SysUITestModule::class, BiometricsDomainLayerModule::class])
+ @Component(
+ modules =
+ [
+ SysUITestModule::class,
+ BiometricsDomainLayerModule::class,
+ UserDomainLayerModule::class,
+ ]
+ )
@SysUISingleton
interface TestComponent : SysUITestComponent<AlwaysOnDisplayNotificationIconsInteractor> {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/DeviceBasedSatelliteRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/DeviceBasedSatelliteRepositoryImplTest.kt
index d24d87c6..890a2e4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/DeviceBasedSatelliteRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/DeviceBasedSatelliteRepositoryImplTest.kt
@@ -34,6 +34,7 @@
import android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_UNKNOWN
import android.telephony.satellite.SatelliteManager.SatelliteException
import android.telephony.satellite.SatelliteModemStateCallback
+import android.telephony.satellite.SatelliteProvisionStateCallback
import android.telephony.satellite.SatelliteSupportedStateCallback
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
@@ -326,6 +327,98 @@
}
@Test
+ fun satelliteProvisioned_notSupported_defaultFalse() =
+ testScope.runTest {
+ // GIVEN satellite is not supported
+ setUpRepo(
+ uptime = MIN_UPTIME,
+ satMan = satelliteManager,
+ satelliteSupported = false,
+ )
+
+ assertThat(underTest.isSatelliteProvisioned.value).isFalse()
+ }
+
+ @Test
+ fun satelliteProvisioned_supported_defaultFalse() =
+ testScope.runTest {
+ // GIVEN satellite is supported
+ setUpRepo(
+ uptime = MIN_UPTIME,
+ satMan = satelliteManager,
+ satelliteSupported = true,
+ )
+
+ // THEN default provisioned state is false
+ assertThat(underTest.isSatelliteProvisioned.value).isFalse()
+ }
+
+ @Test
+ fun satelliteProvisioned_supported_tracksCallback() =
+ testScope.runTest {
+ // GIVEN satellite is not supported
+ setUpRepo(
+ uptime = MIN_UPTIME,
+ satMan = satelliteManager,
+ satelliteSupported = true,
+ )
+
+ val provisioned by collectLastValue(underTest.isSatelliteProvisioned)
+ runCurrent()
+
+ val callback =
+ withArgCaptor<SatelliteProvisionStateCallback> {
+ verify(satelliteManager).registerForProvisionStateChanged(any(), capture())
+ }
+
+ // WHEN provisioning state changes
+ callback.onSatelliteProvisionStateChanged(true)
+
+ // THEN the value is reflected in the repo
+ assertThat(provisioned).isTrue()
+ }
+
+ @Test
+ fun satelliteProvisioned_supported_tracksCallback_reRegistersOnCrash() =
+ testScope.runTest {
+ // GIVEN satellite is supported
+ setUpRepo(
+ uptime = MIN_UPTIME,
+ satMan = satelliteManager,
+ satelliteSupported = true,
+ )
+
+ val provisioned by collectLastValue(underTest.isSatelliteProvisioned)
+
+ runCurrent()
+
+ val callback =
+ withArgCaptor<SatelliteProvisionStateCallback> {
+ verify(satelliteManager).registerForProvisionStateChanged(any(), capture())
+ }
+ val telephonyCallback =
+ MobileTelephonyHelpers.getTelephonyCallbackForType<
+ TelephonyCallback.RadioPowerStateListener
+ >(
+ telephonyManager
+ )
+
+ // GIVEN satellite is currently provisioned
+ callback.onSatelliteProvisionStateChanged(true)
+
+ assertThat(provisioned).isTrue()
+
+ // WHEN a crash event happens (detected by radio state change)
+ telephonyCallback.onRadioPowerStateChanged(TelephonyManager.RADIO_POWER_ON)
+ runCurrent()
+ telephonyCallback.onRadioPowerStateChanged(TelephonyManager.RADIO_POWER_OFF)
+ runCurrent()
+
+ // THEN listeners are re-registered
+ verify(satelliteManager, times(2)).registerForProvisionStateChanged(any(), any())
+ }
+
+ @Test
fun satelliteNotSupported_listenersAreNotRegistered() =
testScope.runTest {
// GIVEN satellite is not supported
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/FakeDeviceBasedSatelliteRepository.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/FakeDeviceBasedSatelliteRepository.kt
index 5fa2d33..55460bd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/FakeDeviceBasedSatelliteRepository.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/FakeDeviceBasedSatelliteRepository.kt
@@ -21,6 +21,8 @@
import kotlinx.coroutines.flow.MutableStateFlow
class FakeDeviceBasedSatelliteRepository() : DeviceBasedSatelliteRepository {
+ override val isSatelliteProvisioned = MutableStateFlow(true)
+
override val connectionState = MutableStateFlow(Off)
override val signalStrength = MutableStateFlow(0)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractorTest.kt
index d303976..2e5ebb3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractorTest.kt
@@ -31,8 +31,6 @@
import com.android.systemui.statusbar.pipeline.wifi.data.repository.FakeWifiRepository
import com.android.systemui.statusbar.pipeline.wifi.domain.interactor.WifiInteractorImpl
import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel
-import com.android.systemui.statusbar.policy.data.repository.FakeDeviceProvisioningRepository
-import com.android.systemui.statusbar.policy.domain.interactor.DeviceProvisioningInteractor
import com.android.systemui.util.mockito.mock
import com.google.common.truth.Truth.assertThat
import kotlin.test.Test
@@ -55,9 +53,6 @@
)
private val repo = FakeDeviceBasedSatelliteRepository()
- private val deviceProvisionedRepository = FakeDeviceProvisioningRepository()
- private val deviceProvisioningInteractor =
- DeviceProvisioningInteractor(deviceProvisionedRepository)
private val connectivityRepository = FakeConnectivityRepository()
private val wifiRepository = FakeWifiRepository()
private val wifiInteractor =
@@ -69,7 +64,6 @@
DeviceBasedSatelliteInteractor(
repo,
iconsInteractor,
- deviceProvisioningInteractor,
wifiInteractor,
testScope.backgroundScope,
FakeLogBuffer.Factory.create(),
@@ -113,7 +107,6 @@
DeviceBasedSatelliteInteractor(
repo,
iconsInteractor,
- deviceProvisioningInteractor,
wifiInteractor,
testScope.backgroundScope,
FakeLogBuffer.Factory.create(),
@@ -162,7 +155,6 @@
DeviceBasedSatelliteInteractor(
repo,
iconsInteractor,
- deviceProvisioningInteractor,
wifiInteractor,
testScope.backgroundScope,
FakeLogBuffer.Factory.create(),
@@ -219,7 +211,6 @@
DeviceBasedSatelliteInteractor(
repo,
iconsInteractor,
- deviceProvisioningInteractor,
wifiInteractor,
testScope.backgroundScope,
FakeLogBuffer.Factory.create(),
@@ -538,7 +529,6 @@
DeviceBasedSatelliteInteractor(
repo,
iconsInteractor,
- deviceProvisioningInteractor,
wifiInteractor,
testScope.backgroundScope,
FakeLogBuffer.Factory.create(),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/ui/viewmodel/DeviceBasedSatelliteViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/ui/viewmodel/DeviceBasedSatelliteViewModelTest.kt
index 43b9568..c39e301 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/ui/viewmodel/DeviceBasedSatelliteViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/ui/viewmodel/DeviceBasedSatelliteViewModelTest.kt
@@ -32,8 +32,6 @@
import com.android.systemui.statusbar.pipeline.wifi.data.repository.FakeWifiRepository
import com.android.systemui.statusbar.pipeline.wifi.domain.interactor.WifiInteractorImpl
import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel
-import com.android.systemui.statusbar.policy.data.repository.FakeDeviceProvisioningRepository
-import com.android.systemui.statusbar.policy.domain.interactor.DeviceProvisioningInteractor
import com.android.systemui.util.mockito.mock
import com.google.common.truth.Truth.assertThat
import kotlin.test.Test
@@ -55,9 +53,6 @@
private val mobileIconsInteractor = FakeMobileIconsInteractor(FakeMobileMappingsProxy(), mock())
- private val deviceProvisionedRepository = FakeDeviceProvisioningRepository()
- private val deviceProvisioningInteractor =
- DeviceProvisioningInteractor(deviceProvisionedRepository)
private val connectivityRepository = FakeConnectivityRepository()
private val wifiRepository = FakeWifiRepository()
private val wifiInteractor =
@@ -72,7 +67,6 @@
DeviceBasedSatelliteInteractor(
repo,
mobileIconsInteractor,
- deviceProvisioningInteractor,
wifiInteractor,
testScope.backgroundScope,
FakeLogBuffer.Factory.create(),
@@ -252,14 +246,14 @@
// GIVEN apm is disabled
airplaneModeRepository.setIsAirplaneMode(false)
- // GIVEN device is not provisioned
- deviceProvisionedRepository.setDeviceProvisioned(false)
+ // GIVEN satellite is not provisioned
+ repo.isSatelliteProvisioned.value = false
// THEN icon is null because the device is not provisioned
assertThat(latest).isNull()
- // GIVEN device becomes provisioned
- deviceProvisionedRepository.setDeviceProvisioned(true)
+ // GIVEN satellite becomes provisioned
+ repo.isSatelliteProvisioned.value = true
// Wait for delay to be completed
advanceTimeBy(10.seconds)
@@ -285,8 +279,8 @@
// GIVEN apm is disabled
airplaneModeRepository.setIsAirplaneMode(false)
- // GIVEN device is provisioned
- deviceProvisionedRepository.setDeviceProvisioned(true)
+ // GIVEN satellite is provisioned
+ repo.isSatelliteProvisioned.value = true
// GIVEN wifi network is active
wifiRepository.setWifiNetwork(WifiNetworkModel.Active(networkId = 0, level = 1))
@@ -474,14 +468,14 @@
// GIVEN apm is disabled
airplaneModeRepository.setIsAirplaneMode(false)
- // GIVEN device is not provisioned
- deviceProvisionedRepository.setDeviceProvisioned(false)
+ // GIVEN satellite is not provisioned
+ repo.isSatelliteProvisioned.value = false
// THEN carrier text is null because the device is not provisioned
assertThat(latest).isNull()
- // GIVEN device becomes provisioned
- deviceProvisionedRepository.setDeviceProvisioned(true)
+ // GIVEN satellite becomes provisioned
+ repo.isSatelliteProvisioned.value = true
// Wait for delay to be completed
advanceTimeBy(10.seconds)
@@ -508,8 +502,8 @@
// GIVEN apm is disabled
airplaneModeRepository.setIsAirplaneMode(false)
- // GIVEN device is provisioned
- deviceProvisionedRepository.setDeviceProvisioned(true)
+ // GIVEN satellite is provisioned
+ repo.isSatelliteProvisioned.value = true
// GIVEN wifi network is active
wifiRepository.setWifiNetwork(WifiNetworkModel.Active(networkId = 0, level = 1))
diff --git a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
index dbdbe65..fac6a4c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
@@ -87,6 +87,7 @@
import com.android.systemui.util.settings.SecureSettings;
import com.android.systemui.util.time.FakeSystemClock;
import com.android.systemui.volume.domain.interactor.VolumePanelNavigationInteractor;
+import com.android.systemui.volume.panel.shared.flag.VolumePanelFlag;
import com.android.systemui.volume.ui.binder.VolumeDialogMenuIconBinder;
import com.android.systemui.volume.ui.navigation.VolumeNavigator;
@@ -119,7 +120,6 @@
View mDrawerNormal;
ViewGroup mDialogRowsView;
CaptionsToggleImageButton mODICaptionsIcon;
-
private TestableLooper mTestableLooper;
private ConfigurationController mConfigurationController;
private int mOriginalOrientation;
@@ -151,6 +151,8 @@
private VolumeNavigator mVolumeNavigator;
@Mock
private VolumeDialogMenuIconBinder mVolumeDialogMenuIconBinder;
+ @Mock
+ private VolumePanelFlag mVolumePanelFlag;
private final CsdWarningDialog.Factory mCsdWarningDialogFactory =
new CsdWarningDialog.Factory() {
@@ -211,6 +213,7 @@
mCsdWarningDialogFactory,
mPostureController,
mTestableLooper.getLooper(),
+ mVolumePanelFlag,
mDumpManager,
mLazySecureSettings,
mVibratorHelper,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/animation/DialogTransitionAnimatorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/animation/DialogTransitionAnimatorKosmos.kt
index 5a092f3..62e56be 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/animation/DialogTransitionAnimatorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/animation/DialogTransitionAnimatorKosmos.kt
@@ -16,16 +16,16 @@
package com.android.systemui.animation
+import android.content.applicationContext
import com.android.systemui.jank.interactionJankMonitor
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.Kosmos.Fixture
-import com.android.systemui.kosmos.testCase
val Kosmos.dialogTransitionAnimator by Fixture {
fakeDialogTransitionAnimator(
// The main thread is checked in a bunch of places inside the different transitions
// animators, so we have to pass the real main executor here.
- mainExecutor = testCase.context.mainExecutor,
+ mainExecutor = applicationContext.mainExecutor,
interactionJankMonitor = interactionJankMonitor,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalSceneRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalSceneRepository.kt
index a7bf87d..d280be2 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalSceneRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalSceneRepository.kt
@@ -6,6 +6,7 @@
import com.android.systemui.communal.shared.model.CommunalScenes
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
@@ -13,20 +14,25 @@
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.launch
/** Fake implementation of [CommunalSceneRepository]. */
@OptIn(ExperimentalCoroutinesApi::class)
class FakeCommunalSceneRepository(
- applicationScope: CoroutineScope,
+ private val applicationScope: CoroutineScope,
override val currentScene: MutableStateFlow<SceneKey> =
MutableStateFlow(CommunalScenes.Default),
) : CommunalSceneRepository {
- override fun changeScene(toScene: SceneKey, transitionKey: TransitionKey?) =
- snapToScene(toScene)
- override fun snapToScene(toScene: SceneKey) {
- this.currentScene.value = toScene
- this._transitionState.value = flowOf(ObservableTransitionState.Idle(toScene))
+ override fun changeScene(toScene: SceneKey, transitionKey: TransitionKey?) =
+ snapToScene(toScene, 0)
+
+ override fun snapToScene(toScene: SceneKey, delayMillis: Long) {
+ applicationScope.launch {
+ delay(delayMillis)
+ currentScene.value = toScene
+ _transitionState.value = flowOf(ObservableTransitionState.Idle(toScene))
+ }
}
private val defaultTransitionState = ObservableTransitionState.Idle(CommunalScenes.Default)
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/haptics/qs/QSLongPressEffectKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/haptics/qs/QSLongPressEffectKosmos.kt
index 24603ef..eff99e04 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/haptics/qs/QSLongPressEffectKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/haptics/qs/QSLongPressEffectKosmos.kt
@@ -17,8 +17,8 @@
package com.android.systemui.haptics.qs
import com.android.systemui.haptics.vibratorHelper
-import com.android.systemui.keyguard.domain.interactor.keyguardInteractor
import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.statusbar.policy.keyguardStateController
val Kosmos.qsLongPressEffect by
- Kosmos.Fixture { QSLongPressEffect(vibratorHelper, keyguardInteractor) }
+ Kosmos.Fixture { QSLongPressEffect(vibratorHelper, keyguardStateController) }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractorKosmos.kt
index 162fd90..28bd439 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractorKosmos.kt
@@ -16,7 +16,6 @@
package com.android.systemui.keyguard.domain.interactor
-import com.android.systemui.flags.featureFlagsClassic
import com.android.systemui.keyguard.data.repository.keyguardTransitionRepository
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.applicationCoroutineScope
@@ -34,7 +33,6 @@
bgDispatcher = testDispatcher,
mainDispatcher = testDispatcher,
keyguardInteractor = keyguardInteractor,
- flags = featureFlagsClassic,
shadeRepository = shadeRepository,
powerInteractor = powerInteractor,
glanceableHubTransitions = glanceableHubTransitions,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractorKosmos.kt
index 98babff..d72b9c1 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractorKosmos.kt
@@ -18,7 +18,6 @@
import com.android.keyguard.keyguardSecurityModel
import com.android.systemui.communal.domain.interactor.communalInteractor
-import com.android.systemui.flags.featureFlagsClassic
import com.android.systemui.keyguard.data.repository.keyguardTransitionRepository
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.applicationCoroutineScope
@@ -37,7 +36,6 @@
mainDispatcher = testDispatcher,
keyguardInteractor = keyguardInteractor,
communalInteractor = communalInteractor,
- flags = featureFlagsClassic,
keyguardSecurityModel = keyguardSecurityModel,
selectedUserInteractor = selectedUserInteractor,
powerInteractor = powerInteractor,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt
index 6d2d04a..45a14ad 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt
@@ -62,6 +62,8 @@
import com.android.systemui.statusbar.notification.stack.domain.interactor.sharedNotificationContainerInteractor
import com.android.systemui.statusbar.phone.scrimController
import com.android.systemui.statusbar.pipeline.mobile.data.repository.fakeMobileConnectionsRepository
+import com.android.systemui.statusbar.pipeline.wifi.data.repository.fakeWifiRepository
+import com.android.systemui.statusbar.pipeline.wifi.domain.interactor.wifiInteractor
import com.android.systemui.statusbar.policy.data.repository.fakeDeviceProvisioningRepository
import com.android.systemui.statusbar.policy.domain.interactor.deviceProvisioningInteractor
import com.android.systemui.util.time.systemClock
@@ -130,6 +132,8 @@
val shadeController by lazy { kosmos.shadeController }
val shadeRepository by lazy { kosmos.shadeRepository }
val shadeInteractor by lazy { kosmos.shadeInteractor }
+ val wifiInteractor by lazy { kosmos.wifiInteractor }
+ val fakeWifiRepository by lazy { kosmos.fakeWifiRepository }
val ongoingActivityChipsViewModel by lazy { kosmos.ongoingActivityChipsViewModel }
val scrimController by lazy { kosmos.scrimController }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/domain/pipeline/interactor/MediaCarouselInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/domain/pipeline/interactor/MediaCarouselInteractorKosmos.kt
index e5e2aff..ca1b3f5 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/domain/pipeline/interactor/MediaCarouselInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/domain/pipeline/interactor/MediaCarouselInteractorKosmos.kt
@@ -18,7 +18,6 @@
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.applicationCoroutineScope
-import com.android.systemui.media.controls.data.repository.mediaDataRepository
import com.android.systemui.media.controls.data.repository.mediaFilterRepository
import com.android.systemui.media.controls.domain.pipeline.mediaDataCombineLatest
import com.android.systemui.media.controls.domain.pipeline.mediaDataFilter
@@ -33,7 +32,6 @@
Kosmos.Fixture {
MediaCarouselInteractor(
applicationScope = applicationCoroutineScope,
- mediaDataRepository = mediaDataRepository,
mediaDataProcessor = mediaDataProcessor,
mediaTimeoutListener = mediaTimeoutListener,
mediaResumeListener = mediaResumeListener,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/interactor/SceneInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/interactor/SceneInteractorKosmos.kt
index d1fbb5e..066736c 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/interactor/SceneInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/interactor/SceneInteractorKosmos.kt
@@ -16,16 +16,12 @@
package com.android.systemui.scene.domain.interactor
-import com.android.compose.animation.scene.SceneKey
-import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor
import com.android.systemui.deviceentry.domain.interactor.deviceUnlockedInteractor
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.applicationCoroutineScope
import com.android.systemui.scene.data.repository.sceneContainerRepository
-import com.android.systemui.scene.domain.resolver.HomeSceneFamilyResolver
-import com.android.systemui.scene.domain.resolver.SceneResolver
+import com.android.systemui.scene.domain.resolver.sceneFamilyResolvers
import com.android.systemui.scene.shared.logger.sceneLogger
-import com.android.systemui.scene.shared.model.SceneFamilies
val Kosmos.sceneInteractor by
Kosmos.Fixture {
@@ -37,14 +33,3 @@
deviceUnlockedInteractor = deviceUnlockedInteractor,
)
}
-
-val Kosmos.sceneFamilyResolvers: Map<SceneKey, SceneResolver>
- get() = mapOf(SceneFamilies.Home to homeSceneFamilyResolver)
-
-val Kosmos.homeSceneFamilyResolver by
- Kosmos.Fixture {
- HomeSceneFamilyResolver(
- applicationScope = applicationCoroutineScope,
- deviceEntryInteractor = deviceEntryInteractor,
- )
- }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/resolver/SceneResolverKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/resolver/SceneResolverKosmos.kt
new file mode 100644
index 0000000..6be1939
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/resolver/SceneResolverKosmos.kt
@@ -0,0 +1,59 @@
+/*
+ * 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.resolver
+
+import com.android.compose.animation.scene.SceneKey
+import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.scene.shared.model.SceneFamilies
+import com.android.systemui.shade.domain.interactor.shadeInteractor
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+
+val Kosmos.sceneFamilyResolvers: Map<SceneKey, SceneResolver>
+ get() =
+ mapOf(
+ SceneFamilies.Home to homeSceneFamilyResolver,
+ SceneFamilies.NotifShade to notifShadeSceneFamilyResolver,
+ SceneFamilies.QuickSettings to quickSettingsSceneFamilyResolver,
+ )
+
+val Kosmos.homeSceneFamilyResolver by
+ Kosmos.Fixture {
+ HomeSceneFamilyResolver(
+ applicationScope = applicationCoroutineScope,
+ deviceEntryInteractor = deviceEntryInteractor,
+ )
+ }
+
+val Kosmos.notifShadeSceneFamilyResolver by
+ Kosmos.Fixture {
+ NotifShadeSceneFamilyResolver(
+ applicationScope = applicationCoroutineScope,
+ shadeInteractor = shadeInteractor,
+ )
+ }
+
+val Kosmos.quickSettingsSceneFamilyResolver by
+ Kosmos.Fixture {
+ QuickSettingsSceneFamilyResolver(
+ applicationScope = applicationCoroutineScope,
+ shadeInteractor = shadeInteractor,
+ )
+ }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ShadeControllerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ShadeControllerKosmos.kt
index cc836ac..0bc4d54 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ShadeControllerKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ShadeControllerKosmos.kt
@@ -23,7 +23,6 @@
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.applicationCoroutineScope
import com.android.systemui.kosmos.testDispatcher
-import com.android.systemui.log.LogBuffer
import com.android.systemui.plugins.statusbar.statusBarStateController
import com.android.systemui.scene.domain.interactor.sceneInteractor
import com.android.systemui.scene.shared.flag.SceneContainerFlag
@@ -50,7 +49,6 @@
shadeInteractor = shadeInteractor,
sceneInteractor = sceneInteractor,
notificationStackScrollLayout = mock<NotificationStackScrollLayout>(),
- touchLog = mock<LogBuffer>(),
vibratorHelper = mock<VibratorHelper>(),
commandQueue = mock<CommandQueue>(),
statusBarKeyguardViewManager = mock<StatusBarKeyguardViewManager>(),
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeLockscreenInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeLockscreenInteractorKosmos.kt
index 0a3a2ee..bcea983 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeLockscreenInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeLockscreenInteractorKosmos.kt
@@ -25,7 +25,6 @@
val Kosmos.shadeLockscreenInteractor by
Kosmos.Fixture {
ShadeLockscreenInteractorImpl(
- applicationScope = applicationCoroutineScope,
backgroundScope = applicationCoroutineScope,
shadeInteractor = shadeInteractorImpl,
sceneInteractor = sceneInteractor,
diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/data/repository/ConnectivityRepositoryKosmos.kt
similarity index 63%
copy from packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogModule.kt
copy to packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/data/repository/ConnectivityRepositoryKosmos.kt
index 2e9169e..8e656cf 100644
--- a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogModule.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/data/repository/ConnectivityRepositoryKosmos.kt
@@ -13,17 +13,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.systemui.bluetooth.qsdialog
-import com.android.systemui.dagger.SysUISingleton
-import dagger.Binds
-import dagger.Module
+package com.android.systemui.statusbar.pipeline.shared.data.repository
-@Module
-interface BluetoothTileDialogModule {
- @Binds
- @SysUISingleton
- fun bindDeviceItemActionInteractor(
- impl: DeviceItemActionInteractorImpl
- ): DeviceItemActionInteractor
-}
+import com.android.systemui.kosmos.Kosmos
+
+val Kosmos.fakeConnectivityRepository: FakeConnectivityRepository by
+ Kosmos.Fixture { FakeConnectivityRepository() }
+val Kosmos.connectivityRepository: ConnectivityRepository by
+ Kosmos.Fixture { fakeConnectivityRepository }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/FakeWifiRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/FakeWifiRepository.kt
similarity index 97%
rename from packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/FakeWifiRepository.kt
rename to packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/FakeWifiRepository.kt
index 97c8d5f..709be5e 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/FakeWifiRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/FakeWifiRepository.kt
@@ -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.
diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositoryKosmos.kt
similarity index 64%
rename from packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogModule.kt
rename to packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositoryKosmos.kt
index 2e9169e..e44061a 100644
--- a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogModule.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositoryKosmos.kt
@@ -13,17 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.systemui.bluetooth.qsdialog
-import com.android.systemui.dagger.SysUISingleton
-import dagger.Binds
-import dagger.Module
+package com.android.systemui.statusbar.pipeline.wifi.data.repository
-@Module
-interface BluetoothTileDialogModule {
- @Binds
- @SysUISingleton
- fun bindDeviceItemActionInteractor(
- impl: DeviceItemActionInteractorImpl
- ): DeviceItemActionInteractor
-}
+import com.android.systemui.kosmos.Kosmos
+
+val Kosmos.fakeWifiRepository: FakeWifiRepository by Kosmos.Fixture { FakeWifiRepository() }
+val Kosmos.wifiRepository: WifiRepository by Kosmos.Fixture { fakeWifiRepository }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractorKosmos.kt
new file mode 100644
index 0000000..7036199
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractorKosmos.kt
@@ -0,0 +1,31 @@
+/*
+ * 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.pipeline.wifi.domain.interactor
+
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.statusbar.pipeline.shared.data.repository.connectivityRepository
+import com.android.systemui.statusbar.pipeline.wifi.data.repository.wifiRepository
+
+val Kosmos.wifiInteractor: WifiInteractor by
+ Kosmos.Fixture {
+ WifiInteractorImpl(
+ connectivityRepository,
+ wifiRepository,
+ applicationCoroutineScope,
+ )
+ }
diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/popup/ui/composable/VolumePanelPopupKosmos.kt
similarity index 61%
copy from packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogModule.kt
copy to packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/popup/ui/composable/VolumePanelPopupKosmos.kt
index 2e9169e..49170d8 100644
--- a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogModule.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/popup/ui/composable/VolumePanelPopupKosmos.kt
@@ -13,17 +13,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.systemui.bluetooth.qsdialog
-import com.android.systemui.dagger.SysUISingleton
-import dagger.Binds
-import dagger.Module
+package com.android.systemui.volume.panel.component.popup.ui.composable
-@Module
-interface BluetoothTileDialogModule {
- @Binds
- @SysUISingleton
- fun bindDeviceItemActionInteractor(
- impl: DeviceItemActionInteractorImpl
- ): DeviceItemActionInteractor
-}
+import com.android.systemui.animation.dialogTransitionAnimator
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.statusbar.phone.systemUIDialogFactory
+
+val Kosmos.volumePanelPopup: VolumePanelPopup by
+ Kosmos.Fixture { VolumePanelPopup(systemUIDialogFactory, dialogTransitionAnimator) }
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/RotationChangeProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/RotationChangeProvider.kt
index 4f3aee9..fec6ff1 100644
--- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/RotationChangeProvider.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/RotationChangeProvider.kt
@@ -27,6 +27,7 @@
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
+import java.util.concurrent.CopyOnWriteArrayList
/**
* Allows to subscribe to rotation changes. Updates are provided for the display associated to
@@ -41,7 +42,7 @@
@Assisted private val callbackHandler: Handler,
) : CallbackController<RotationChangeProvider.RotationListener> {
- private val listeners = mutableListOf<RotationListener>()
+ private val listeners = CopyOnWriteArrayList<RotationListener>()
private val displayListener = RotationDisplayListener()
private var lastRotation: Int? = null
diff --git a/packages/WAPPushManager/src/com/android/smspush/WapPushManager.java b/packages/WAPPushManager/src/com/android/smspush/WapPushManager.java
old mode 100755
new mode 100644
diff --git a/packages/WallpaperCropper/res/drawable-hdpi/ic_actionbar_accept.png b/packages/WallpaperCropper/res/drawable-hdpi/ic_actionbar_accept.png
old mode 100755
new mode 100644
Binary files differ
diff --git a/packages/WallpaperCropper/res/drawable-mdpi/ic_actionbar_accept.png b/packages/WallpaperCropper/res/drawable-mdpi/ic_actionbar_accept.png
old mode 100755
new mode 100644
Binary files differ
diff --git a/packages/WallpaperCropper/res/drawable-xhdpi/ic_actionbar_accept.png b/packages/WallpaperCropper/res/drawable-xhdpi/ic_actionbar_accept.png
old mode 100755
new mode 100644
Binary files differ
diff --git a/services/accessibility/java/com/android/server/accessibility/UiAutomationManager.java b/services/accessibility/java/com/android/server/accessibility/UiAutomationManager.java
index 9593006..f85d786 100644
--- a/services/accessibility/java/com/android/server/accessibility/UiAutomationManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/UiAutomationManager.java
@@ -101,8 +101,10 @@
SystemActionPerformer systemActionPerformer,
AccessibilityWindowManager awm, int flags) {
accessibilityServiceInfo.setComponentName(COMPONENT_NAME);
- Slogf.i(LOG_TAG, "Registering UiTestAutomationService (id=%s) when called by user %d",
- accessibilityServiceInfo.getId(), Binder.getCallingUserHandle().getIdentifier());
+ Slogf.i(LOG_TAG, "Registering UiTestAutomationService (id=%s, flags=0x%x) when"
+ + " called by user %d",
+ accessibilityServiceInfo.getId(), flags,
+ Binder.getCallingUserHandle().getIdentifier());
if (mUiAutomationService != null) {
throw new IllegalStateException(
"UiAutomationService " + mUiAutomationService.mServiceInterface
diff --git a/services/autofill/java/com/android/server/autofill/ui/FillUi.java b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
index 78edb8e..1831ecd 100644
--- a/services/autofill/java/com/android/server/autofill/ui/FillUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
@@ -689,12 +689,20 @@
Slog.v(TAG, "AutofillWindowPresenter.show(): fit=" + fitsSystemWindows
+ ", params=" + paramsToString(p));
}
- UiThread.getHandler().post(() -> mWindow.show(p));
+ UiThread.getHandler().post(() -> {
+ if (mWindow != null) {
+ mWindow.show(p);
+ }
+ });
}
@Override
public void hide(Rect transitionEpicenter) {
- UiThread.getHandler().post(mWindow::hide);
+ UiThread.getHandler().post(() -> {
+ if (mWindow != null) {
+ mWindow.hide();
+ }
+ });
}
}
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 167c384..53730e3 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -227,6 +227,7 @@
"connectivity_flags_lib",
"dreams_flags_lib",
"aconfig_new_storage_flags_lib",
+ "powerstats_flags_lib",
],
javac_shard_size: 50,
javacflags: [
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 0c1d0fb..e424ffa 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -3892,9 +3892,10 @@
return;
}
- final long lastTopTime = sr.app.mState.getLastTopTime();
- final long constantTimeLimit = getTimeLimitForFgsType(fgsType);
+ final boolean currentlyTop = sr.app.mState.getCurProcState() <= PROCESS_STATE_TOP;
final long nowUptime = SystemClock.uptimeMillis();
+ final long lastTopTime = currentlyTop ? nowUptime : sr.app.mState.getLastTopTime();
+ final long constantTimeLimit = getTimeLimitForFgsType(fgsType);
if (lastTopTime != Long.MIN_VALUE && constantTimeLimit > (nowUptime - lastTopTime)) {
// Discard any other messages for this service
mAm.mHandler.removeMessages(ActivityManagerService.SERVICE_FGS_TIMEOUT_MSG, sr);
@@ -6290,7 +6291,7 @@
final ComponentName clientSideComponentName =
cr.aliasComponent != null ? cr.aliasComponent : r.name;
try {
- cr.conn.connected(r.name, null, true);
+ cr.conn.connected(clientSideComponentName, null, true);
} catch (Exception e) {
Slog.w(TAG, "Failure disconnecting service " + r.shortInstanceName
+ " to connection " + c.get(i).conn.asBinder()
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index 26aa053..2c04883 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -169,6 +169,11 @@
*/
static final String KEY_ENABLE_NEW_OOMADJ = "enable_new_oom_adj";
+ /**
+ * Whether or not to enable the batching of OOM adjuster calls to LMKD
+ */
+ static final String KEY_ENABLE_BATCHING_OOM_ADJ = "enable_batching_oom_adj";
+
private static final int DEFAULT_MAX_CACHED_PROCESSES = 1024;
private static final boolean DEFAULT_PRIORITIZE_ALARM_BROADCASTS = true;
private static final long DEFAULT_FGSERVICE_MIN_SHOWN_TIME = 2*1000;
@@ -244,6 +249,11 @@
private static final boolean DEFAULT_ENABLE_NEW_OOM_ADJ = Flags.oomadjusterCorrectnessRewrite();
/**
+ * The default value to {@link #KEY_ENABLE_BATCHING_OOM_ADJ}.
+ */
+ private static final boolean DEFAULT_ENABLE_BATCHING_OOM_ADJ = Flags.batchingOomAdj();
+
+ /**
* Same as {@link TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_NOT_ALLOWED}
*/
private static final int
@@ -1136,6 +1146,9 @@
/** @see #KEY_ENABLE_NEW_OOMADJ */
public boolean ENABLE_NEW_OOMADJ = DEFAULT_ENABLE_NEW_OOM_ADJ;
+ /** @see #KEY_ENABLE_BATCHING_OOM_ADJ */
+ public boolean ENABLE_BATCHING_OOM_ADJ = DEFAULT_ENABLE_BATCHING_OOM_ADJ;
+
/**
* Indicates whether PSS profiling in AppProfiler is disabled or not.
*/
@@ -1479,6 +1492,8 @@
private void loadNativeBootDeviceConfigConstants() {
ENABLE_NEW_OOMADJ = getDeviceConfigBoolean(KEY_ENABLE_NEW_OOMADJ,
DEFAULT_ENABLE_NEW_OOM_ADJ);
+ ENABLE_BATCHING_OOM_ADJ = getDeviceConfigBoolean(KEY_ENABLE_BATCHING_OOM_ADJ,
+ DEFAULT_ENABLE_BATCHING_OOM_ADJ);
}
public void setOverrideMaxCachedProcesses(int value) {
@@ -2248,6 +2263,13 @@
mDefaultPssToRssThresholdModifier);
}
+ private void updateEnableBatchingOomAdj() {
+ ENABLE_BATCHING_OOM_ADJ = DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT,
+ KEY_ENABLE_BATCHING_OOM_ADJ,
+ DEFAULT_ENABLE_BATCHING_OOM_ADJ);
+ }
+
boolean shouldDebugUidForProcState(int uid) {
SparseBooleanArray ar = mProcStateDebugUids;
final var size = ar.size();
@@ -2476,6 +2498,9 @@
pw.print(" "); pw.print(KEY_MAX_PREVIOUS_TIME);
pw.print("="); pw.println(MAX_PREVIOUS_TIME);
+ pw.print(" "); pw.print(KEY_ENABLE_BATCHING_OOM_ADJ);
+ pw.print("="); pw.println(ENABLE_BATCHING_OOM_ADJ);
+
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 d79d198..44e522f 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -3933,11 +3933,28 @@
+ packageName + ": " + e);
}
if (mUserController.isUserRunning(user, userRunningFlags)) {
+
+ String description;
+ if (reason == null) {
+ description = "from pid " + callingPid;
+
+ // Add the name of the process if it's available
+ final ProcessRecord callerApp;
+ synchronized (mPidsSelfLocked) {
+ callerApp = mPidsSelfLocked.get(callingPid);
+ }
+ if (callerApp != null) {
+ description += " (" + callerApp.processName + ")";
+ }
+ } else {
+ description = reason;
+ }
+
forceStopPackageLocked(packageName, UserHandle.getAppId(pkgUid),
false /* callerWillRestart */, false /* purgeCache */,
true /* doIt */, false /* evenPersistent */,
- false /* uninstalling */, true /* packageStateStopped */, user,
- reason == null ? ("from pid " + callingPid) : reason);
+ false /* uninstalling */, true /* packageStateStopped */,
+ user, description);
finishForceStopPackageLocked(packageName, pkgUid);
}
}
@@ -10207,19 +10224,6 @@
addStartInfoTimestampInternal(key, timestampNs, userId, callingUid);
}
- @Override
- public void reportStartInfoViewTimestamps(long renderThreadDrawStartTimeNs,
- long framePresentedTimeNs) {
- int callingUid = Binder.getCallingUid();
- int userId = UserHandle.getUserId(callingUid);
- addStartInfoTimestampInternal(
- ApplicationStartInfo.START_TIMESTAMP_INITIAL_RENDERTHREAD_FRAME,
- renderThreadDrawStartTimeNs, userId, callingUid);
- addStartInfoTimestampInternal(
- ApplicationStartInfo.START_TIMESTAMP_SURFACEFLINGER_COMPOSITION_COMPLETE,
- framePresentedTimeNs, userId, callingUid);
- }
-
private void addStartInfoTimestampInternal(int key, long timestampNs, int userId, int uid) {
mProcessList.getAppStartInfoTracker().addTimestampToStart(
Settings.getPackageNameForUid(mContext, uid),
diff --git a/services/core/java/com/android/server/am/AppStartInfoTracker.java b/services/core/java/com/android/server/am/AppStartInfoTracker.java
index dc6e2fa3..3042b2a 100644
--- a/services/core/java/com/android/server/am/AppStartInfoTracker.java
+++ b/services/core/java/com/android/server/am/AppStartInfoTracker.java
@@ -89,6 +89,14 @@
@VisibleForTesting static final int APP_START_INFO_HISTORY_LIST_SIZE = 16;
+ /**
+ * The max number of records that can be present in {@link mInProgressRecords}.
+ *
+ * The magic number of 5 records is expected to be enough because this covers in progress
+ * activity starts only, of which more than a 1-2 at a time is very uncommon/unlikely.
+ */
+ @VisibleForTesting static final int MAX_IN_PROGRESS_RECORDS = 5;
+
private static final int APP_START_INFO_MONITORING_MODE_LIST_SIZE = 100;
@VisibleForTesting static final String APP_START_STORE_DIR = "procstartstore";
@@ -147,7 +155,6 @@
/** The path to the historical proc start info file, persisted in the storage. */
@VisibleForTesting File mProcStartInfoFile;
-
/**
* Temporary list of records that have not been completed.
*
@@ -155,7 +162,12 @@
*/
@GuardedBy("mLock")
@VisibleForTesting
- final ArrayMap<Long, ApplicationStartInfo> mInProgRecords = new ArrayMap<>();
+ final ArrayMap<Long, ApplicationStartInfo> mInProgressRecords = new ArrayMap<>();
+
+ /** Temporary list of keys present in {@link mInProgressRecords} for sorting. */
+ @GuardedBy("mLock")
+ @VisibleForTesting
+ final ArrayList<Integer> mTemporaryInProgressIndexes = new ArrayList<>();
AppStartInfoTracker() {
mCallbacks = new SparseArray<>();
@@ -193,6 +205,60 @@
});
}
+ /**
+ * Trim in progress records structure to acceptable size. To be called after each time a new
+ * record is added.
+ *
+ * This is necessary both for robustness, as well as because the call to
+ * {@link onReportFullyDrawn} which triggers the removal in the success case is not guaranteed.
+ *
+ * <p class="note"> Note: this is the expected path for removal of in progress records for
+ * successful activity triggered starts that don't report fully drawn. It is *not* only an edge
+ * case.</p>
+ */
+ @GuardedBy("mLock")
+ private void maybeTrimInProgressRecordsLocked() {
+ if (mInProgressRecords.size() <= MAX_IN_PROGRESS_RECORDS) {
+ // Size is acceptable, do nothing.
+ return;
+ }
+
+ // Make sure the temporary list is empty.
+ mTemporaryInProgressIndexes.clear();
+
+ // Populate the list with indexes for size of {@link mInProgressRecords}.
+ for (int i = 0; i < mInProgressRecords.size(); i++) {
+ mTemporaryInProgressIndexes.add(i, i);
+ }
+
+ // Sort the index collection by value of the corresponding key in {@link mInProgressRecords}
+ // from smallest to largest.
+ Collections.sort(mTemporaryInProgressIndexes, (a, b) -> Long.compare(
+ mInProgressRecords.keyAt(a), mInProgressRecords.keyAt(b)));
+
+ if (mTemporaryInProgressIndexes.size() == MAX_IN_PROGRESS_RECORDS + 1) {
+ // Only removing a single record so don't bother sorting again as we don't have to worry
+ // about indexes changing.
+ mInProgressRecords.removeAt(mTemporaryInProgressIndexes.get(0));
+ } else {
+ // Removing more than 1 record, remove the records we want to keep from the list and
+ // then sort again so we can remove in reverse order of indexes.
+ mTemporaryInProgressIndexes.subList(
+ mTemporaryInProgressIndexes.size() - MAX_IN_PROGRESS_RECORDS,
+ mTemporaryInProgressIndexes.size()).clear();
+ Collections.sort(mTemporaryInProgressIndexes);
+
+ // Remove all remaining record indexes in reverse order to avoid changing the already
+ // calculated indexes.
+ for (int i = mTemporaryInProgressIndexes.size() - 1; i >= 0; i--) {
+ mInProgressRecords.removeAt(mTemporaryInProgressIndexes.get(i));
+ }
+ }
+
+ // Clear the temorary list.
+ mTemporaryInProgressIndexes.clear();
+ }
+
void onIntentStarted(@NonNull Intent intent, long timestampNanos) {
synchronized (mLock) {
if (!mEnabled) {
@@ -211,7 +277,8 @@
} else {
start.setReason(ApplicationStartInfo.START_REASON_START_ACTIVITY);
}
- mInProgRecords.put(timestampNanos, start);
+ mInProgressRecords.put(timestampNanos, start);
+ maybeTrimInProgressRecordsLocked();
}
}
@@ -220,17 +287,17 @@
if (!mEnabled) {
return;
}
- int index = mInProgRecords.indexOfKey(id);
+ int index = mInProgressRecords.indexOfKey(id);
if (index < 0) {
return;
}
- ApplicationStartInfo info = mInProgRecords.valueAt(index);
+ ApplicationStartInfo info = mInProgressRecords.valueAt(index);
if (info == null) {
- mInProgRecords.removeAt(index);
+ mInProgressRecords.removeAt(index);
return;
}
info.setStartupState(ApplicationStartInfo.STARTUP_STATE_ERROR);
- mInProgRecords.removeAt(index);
+ mInProgressRecords.removeAt(index);
}
}
@@ -239,13 +306,13 @@
if (!mEnabled) {
return;
}
- int index = mInProgRecords.indexOfKey(id);
+ int index = mInProgressRecords.indexOfKey(id);
if (index < 0) {
return;
}
- ApplicationStartInfo info = mInProgRecords.valueAt(index);
+ ApplicationStartInfo info = mInProgressRecords.valueAt(index);
if (info == null || app == null) {
- mInProgRecords.removeAt(index);
+ mInProgressRecords.removeAt(index);
return;
}
info.setStartType((int) temperature);
@@ -254,9 +321,9 @@
if (newInfo == null) {
// newInfo can be null if records are added before load from storage is
// complete. In this case the newly added record will be lost.
- mInProgRecords.removeAt(index);
+ mInProgressRecords.removeAt(index);
} else {
- mInProgRecords.setValueAt(index, newInfo);
+ mInProgressRecords.setValueAt(index, newInfo);
}
}
}
@@ -266,17 +333,17 @@
if (!mEnabled) {
return;
}
- int index = mInProgRecords.indexOfKey(id);
+ int index = mInProgressRecords.indexOfKey(id);
if (index < 0) {
return;
}
- ApplicationStartInfo info = mInProgRecords.valueAt(index);
+ ApplicationStartInfo info = mInProgressRecords.valueAt(index);
if (info == null) {
- mInProgRecords.removeAt(index);
+ mInProgressRecords.removeAt(index);
return;
}
info.setStartupState(ApplicationStartInfo.STARTUP_STATE_ERROR);
- mInProgRecords.removeAt(index);
+ mInProgressRecords.removeAt(index);
}
}
@@ -286,13 +353,13 @@
if (!mEnabled) {
return;
}
- int index = mInProgRecords.indexOfKey(id);
+ int index = mInProgressRecords.indexOfKey(id);
if (index < 0) {
return;
}
- ApplicationStartInfo info = mInProgRecords.valueAt(index);
+ ApplicationStartInfo info = mInProgressRecords.valueAt(index);
if (info == null) {
- mInProgRecords.removeAt(index);
+ mInProgressRecords.removeAt(index);
return;
}
info.setLaunchMode(launchMode);
@@ -308,18 +375,18 @@
if (!mEnabled) {
return;
}
- int index = mInProgRecords.indexOfKey(id);
+ int index = mInProgressRecords.indexOfKey(id);
if (index < 0) {
return;
}
- ApplicationStartInfo info = mInProgRecords.valueAt(index);
+ ApplicationStartInfo info = mInProgressRecords.valueAt(index);
if (info == null) {
- mInProgRecords.removeAt(index);
+ mInProgressRecords.removeAt(index);
return;
}
info.addStartupTimestamp(ApplicationStartInfo.START_TIMESTAMP_FULLY_DRAWN,
timestampNanos);
- mInProgRecords.removeAt(index);
+ mInProgressRecords.removeAt(index);
}
}
@@ -964,7 +1031,7 @@
mProcStartInfoFile.delete();
}
mData.getMap().clear();
- mInProgRecords.clear();
+ mInProgressRecords.clear();
}
}
@@ -1128,8 +1195,21 @@
// Records are sorted newest to oldest, grab record at index 0.
ApplicationStartInfo startInfo = mInfos.get(0);
+ int startupState = startInfo.getStartupState();
- if (!isAddTimestampAllowed(startInfo, key, timestampNs)) {
+ // If startup state is error then don't accept any further timestamps.
+ if (startupState == ApplicationStartInfo.STARTUP_STATE_ERROR) {
+ if (DEBUG) Slog.d(TAG, "Startup state is error, not accepting new timestamps.");
+ return;
+ }
+
+ // If startup state is first frame drawn then only accept fully drawn timestamp.
+ if (startupState == ApplicationStartInfo.STARTUP_STATE_FIRST_FRAME_DRAWN
+ && key != ApplicationStartInfo.START_TIMESTAMP_FULLY_DRAWN) {
+ if (DEBUG) {
+ Slog.d(TAG, "Startup state is first frame drawn and timestamp is not fully "
+ + "drawn, not accepting new timestamps.");
+ }
return;
}
@@ -1142,55 +1222,6 @@
}
}
- private boolean isAddTimestampAllowed(ApplicationStartInfo startInfo, int key,
- long timestampNs) {
- int startupState = startInfo.getStartupState();
-
- // If startup state is error then don't accept any further timestamps.
- if (startupState == ApplicationStartInfo.STARTUP_STATE_ERROR) {
- if (DEBUG) Slog.d(TAG, "Startup state is error, not accepting new timestamps.");
- return false;
- }
-
- Map<Integer, Long> timestamps = startInfo.getStartupTimestamps();
-
- if (startupState == ApplicationStartInfo.STARTUP_STATE_FIRST_FRAME_DRAWN) {
- switch (key) {
- case ApplicationStartInfo.START_TIMESTAMP_FULLY_DRAWN:
- // Allowed, continue to confirm it's not already added.
- break;
- case ApplicationStartInfo.START_TIMESTAMP_INITIAL_RENDERTHREAD_FRAME:
- Long firstFrameTimeNs = timestamps
- .get(ApplicationStartInfo.START_TIMESTAMP_FIRST_FRAME);
- if (firstFrameTimeNs == null) {
- // This should never happen. State can't be first frame drawn if first
- // frame timestamp was not provided.
- return false;
- }
-
- if (timestampNs > firstFrameTimeNs) {
- // Initial renderthread frame has to occur before first frame.
- return false;
- }
-
- // Allowed, continue to confirm it's not already added.
- break;
- case ApplicationStartInfo.START_TIMESTAMP_SURFACEFLINGER_COMPOSITION_COMPLETE:
- // Allowed, continue to confirm it's not already added.
- break;
- default:
- return false;
- }
- }
-
- if (timestamps.get(key) != null) {
- // Timestamp should not occur more than once for a given start.
- return false;
- }
-
- return true;
- }
-
@GuardedBy("mLock")
void dumpLocked(PrintWriter pw, String prefix, SimpleDateFormat sdf) {
if (mMonitoringModeEnabled) {
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 29e0f7a..1ac37ad 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -128,8 +128,10 @@
import com.android.server.power.stats.BatteryStatsImpl;
import com.android.server.power.stats.BatteryUsageStatsProvider;
import com.android.server.power.stats.BluetoothPowerStatsProcessor;
+import com.android.server.power.stats.CameraPowerStatsProcessor;
import com.android.server.power.stats.CpuPowerStatsProcessor;
import com.android.server.power.stats.FlashlightPowerStatsProcessor;
+import com.android.server.power.stats.GnssPowerStatsProcessor;
import com.android.server.power.stats.MobileRadioPowerStatsProcessor;
import com.android.server.power.stats.PhoneCallPowerStatsProcessor;
import com.android.server.power.stats.PowerStatsAggregator;
@@ -528,8 +530,7 @@
AggregatedPowerStatsConfig.STATE_SCREEN,
AggregatedPowerStatsConfig.STATE_PROCESS_STATE)
.setProcessor(
- new AudioPowerStatsProcessor(mPowerProfile,
- mPowerStatsUidResolver));
+ new AudioPowerStatsProcessor(mPowerProfile, mPowerStatsUidResolver));
config.trackPowerComponent(BatteryConsumer.POWER_COMPONENT_VIDEO)
.trackDeviceStates(
@@ -539,9 +540,7 @@
AggregatedPowerStatsConfig.STATE_POWER,
AggregatedPowerStatsConfig.STATE_SCREEN,
AggregatedPowerStatsConfig.STATE_PROCESS_STATE)
- .setProcessor(
- new VideoPowerStatsProcessor(mPowerProfile,
- mPowerStatsUidResolver));
+ .setProcessor(new VideoPowerStatsProcessor(mPowerProfile, mPowerStatsUidResolver));
config.trackPowerComponent(BatteryConsumer.POWER_COMPONENT_FLASHLIGHT)
.trackDeviceStates(
@@ -552,8 +551,29 @@
AggregatedPowerStatsConfig.STATE_SCREEN,
AggregatedPowerStatsConfig.STATE_PROCESS_STATE)
.setProcessor(
- new FlashlightPowerStatsProcessor(mPowerProfile,
- mPowerStatsUidResolver));
+ new FlashlightPowerStatsProcessor(mPowerProfile, mPowerStatsUidResolver));
+
+ config.trackPowerComponent(BatteryConsumer.POWER_COMPONENT_CAMERA)
+ .trackDeviceStates(
+ AggregatedPowerStatsConfig.STATE_POWER,
+ AggregatedPowerStatsConfig.STATE_SCREEN)
+ .trackUidStates(
+ AggregatedPowerStatsConfig.STATE_POWER,
+ AggregatedPowerStatsConfig.STATE_SCREEN,
+ AggregatedPowerStatsConfig.STATE_PROCESS_STATE)
+ .setProcessor(
+ new CameraPowerStatsProcessor(mPowerProfile, mPowerStatsUidResolver));
+
+ config.trackPowerComponent(BatteryConsumer.POWER_COMPONENT_GNSS)
+ .trackDeviceStates(
+ AggregatedPowerStatsConfig.STATE_POWER,
+ AggregatedPowerStatsConfig.STATE_SCREEN)
+ .trackUidStates(
+ AggregatedPowerStatsConfig.STATE_POWER,
+ AggregatedPowerStatsConfig.STATE_SCREEN,
+ AggregatedPowerStatsConfig.STATE_PROCESS_STATE)
+ .setProcessor(
+ new GnssPowerStatsProcessor(mPowerProfile, mPowerStatsUidResolver));
return config;
}
@@ -639,6 +659,12 @@
BatteryConsumer.POWER_COMPONENT_FLASHLIGHT,
Flags.streamlinedMiscBatteryStats());
+ mStats.setPowerStatsCollectorEnabled(BatteryConsumer.POWER_COMPONENT_CAMERA,
+ Flags.streamlinedMiscBatteryStats());
+ mBatteryUsageStatsProvider.setPowerStatsExporterEnabled(
+ BatteryConsumer.POWER_COMPONENT_CAMERA,
+ Flags.streamlinedMiscBatteryStats());
+
mWorker.systemServicesReady();
mStats.systemServicesReady(mContext);
mCpuWakeupStats.systemServicesReady();
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index ab34dd4..fc81d3e 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -384,6 +384,13 @@
protected final ArraySet<ProcessRecord> mProcessesInCycle = new ArraySet<>();
/**
+ * List of processes that we want to batch for LMKD to adjust their respective
+ * OOM scores.
+ */
+ @GuardedBy("mService")
+ protected final ArrayList<ProcessRecord> mProcsToOomAdj = new ArrayList<ProcessRecord>();
+
+ /**
* Flag to mark if there is an ongoing oomAdjUpdate: potentially the oomAdjUpdate
* could be called recursively because of the indirect calls during the update;
* however the oomAdjUpdate itself doesn't support recursion - in this case we'd
@@ -1246,7 +1253,7 @@
if (!app.isKilledByAm() && app.getThread() != null) {
// We don't need to apply the update for the process which didn't get computed
if (state.getCompletedAdjSeq() == mAdjSeq) {
- applyOomAdjLSP(app, doingAll, now, nowElapsed, oomAdjReason);
+ applyOomAdjLSP(app, doingAll, now, nowElapsed, oomAdjReason, true);
}
if (app.isPendingFinishAttach()) {
@@ -1348,6 +1355,11 @@
}
}
+ if (!mProcsToOomAdj.isEmpty()) {
+ ProcessList.batchSetOomAdj(mProcsToOomAdj);
+ mProcsToOomAdj.clear();
+ }
+
if (proactiveKillsEnabled // Proactive kills enabled?
&& doKillExcessiveProcesses // Should kill excessive processes?
&& freeSwapPercent < lowSwapThresholdPercent // Swap below threshold?
@@ -3246,10 +3258,16 @@
mCachedAppOptimizer.onWakefulnessChanged(wakefulness);
}
+ @GuardedBy({"mService", "mProcLock"})
+ protected boolean applyOomAdjLSP(ProcessRecord app, boolean doingAll, long now,
+ long nowElapsed, @OomAdjReason int oomAdjReason) {
+ return applyOomAdjLSP(app, doingAll, now, nowElapsed, oomAdjReason, false);
+ }
+
/** Applies the computed oomadj, procstate and sched group values and freezes them in set* */
@GuardedBy({"mService", "mProcLock"})
protected boolean applyOomAdjLSP(ProcessRecord app, boolean doingAll, long now,
- long nowElapsed, @OomAdjReason int oomAdjReson) {
+ long nowElapsed, @OomAdjReason int oomAdjReson, boolean isBatchingOomAdj) {
boolean success = true;
final ProcessStateRecord state = app.mState;
final UidRecord uidRec = app.getUidRecord();
@@ -3266,7 +3284,12 @@
final int oldOomAdj = state.getSetAdj();
if (state.getCurAdj() != state.getSetAdj()) {
- ProcessList.setOomAdj(app.getPid(), app.uid, state.getCurAdj());
+ if (isBatchingOomAdj && mConstants.ENABLE_BATCHING_OOM_ADJ) {
+ mProcsToOomAdj.add(app);
+ } else {
+ ProcessList.setOomAdj(app.getPid(), app.uid, state.getCurAdj());
+ }
+
if (DEBUG_SWITCH || DEBUG_OOM_ADJ || mService.mCurOomAdjUid == app.info.uid) {
String msg = "Set " + app.getPid() + " " + app.processName + " adj "
+ state.getCurAdj() + ": " + state.getAdjType();
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 219de70..c094724 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -354,6 +354,7 @@
// LMK_KILL_OCCURRED
// LMK_START_MONITORING
// LMK_BOOT_COMPLETED
+ // LMK_PROCS_PRIO
static final byte LMK_TARGET = 0;
static final byte LMK_PROCPRIO = 1;
static final byte LMK_PROCREMOVE = 2;
@@ -365,6 +366,7 @@
static final byte LMK_KILL_OCCURRED = 8; // Msg to subscribed clients on kill occurred event
static final byte LMK_START_MONITORING = 9; // Start monitoring if delayed earlier
static final byte LMK_BOOT_COMPLETED = 10;
+ static final byte LMK_PROCS_PRIO = 11; // Batch option for LMK_PROCPRIO
// Low Memory Killer Daemon command codes.
// These must be kept in sync with async_event_type definitions in lmkd.h
@@ -1561,6 +1563,50 @@
}
}
+
+ // The max size for PROCS_PRIO cmd in LMKD
+ private static final int MAX_PROCS_PRIO_PACKET_SIZE = 3;
+
+ // (4 bytes per field * 4 fields * 3 processes per batch) + 4 bytes for the LMKD cmd
+ private static final int MAX_OOM_ADJ_BATCH_LENGTH = ((4 * 4) * MAX_PROCS_PRIO_PACKET_SIZE) + 4;
+
+ /**
+ * Set the out-of-memory badness adjustment for a list of processes.
+ *
+ * @param apps App list to adjust their respective oom score.
+ *
+ * {@hide}
+ */
+ public static void batchSetOomAdj(ArrayList<ProcessRecord> apps) {
+ final int totalApps = apps.size();
+ if (totalApps == 0) {
+ return;
+ }
+
+ ByteBuffer buf = ByteBuffer.allocate(MAX_OOM_ADJ_BATCH_LENGTH);
+ int total_procs_in_buf = 0;
+ buf.putInt(LMK_PROCS_PRIO);
+ for (int i = 0; i < totalApps; i++) {
+ final int pid = apps.get(i).getPid();
+ final int amt = apps.get(i).mState.getCurAdj();
+ final int uid = apps.get(i).uid;
+ if (pid <= 0 || amt == UNKNOWN_ADJ) continue;
+ if (total_procs_in_buf >= MAX_PROCS_PRIO_PACKET_SIZE) {
+ writeLmkd(buf, null);
+ buf.clear();
+ total_procs_in_buf = 0;
+ buf.allocate(MAX_OOM_ADJ_BATCH_LENGTH);
+ buf.putInt(LMK_PROCS_PRIO);
+ }
+ buf.putInt(pid);
+ buf.putInt(uid);
+ buf.putInt(amt);
+ buf.putInt(0); // Default proc type to PROC_TYPE_APP
+ total_procs_in_buf++;
+ }
+ writeLmkd(buf, null);
+ }
+
/*
* {@hide}
*/
diff --git a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
index 9a3b575..3df5687 100644
--- a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
+++ b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
@@ -172,6 +172,7 @@
"haptics",
"hardware_backed_security_mainline",
"input",
+ "llvm_and_toolchains",
"lse_desktop_experience",
"machine_learning",
"mainline_modularization",
diff --git a/services/core/java/com/android/server/am/flags.aconfig b/services/core/java/com/android/server/am/flags.aconfig
index afde4f7..2abfad9 100644
--- a/services/core/java/com/android/server/am/flags.aconfig
+++ b/services/core/java/com/android/server/am/flags.aconfig
@@ -134,3 +134,11 @@
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ name: "batching_oom_adj"
+ namespace: "backstage_power"
+ description: "Batch OOM adjustment calls to LMKD"
+ bug: "244232958"
+ is_fixed_read_only: true
+}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index c7ddccc..5dd1480 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -10331,7 +10331,7 @@
try {
if (!permissionOverridesCheck && mHardeningEnforcer.blockFocusMethod(uid,
HardeningEnforcer.METHOD_AUDIO_MANAGER_REQUEST_AUDIO_FOCUS,
- clientId, durationHint, callingPackageName)) {
+ clientId, durationHint, callingPackageName, attributionTag, sdk)) {
final String reason = "Audio focus request blocked by hardening";
Log.w(TAG, reason);
mmi.set(MediaMetrics.Property.EARLY_RETURN, reason).record();
@@ -10343,7 +10343,7 @@
mmi.record();
return mMediaFocusControl.requestAudioFocus(aa, durationHint, cb, fd,
- clientId, callingPackageName, attributionTag, flags, sdk,
+ clientId, callingPackageName, flags, sdk,
forceFocusDuckingForAccessibility(aa, durationHint, uid), -1 /*testUid, ignored*/,
permissionOverridesCheck);
}
@@ -10361,7 +10361,7 @@
return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
}
return mMediaFocusControl.requestAudioFocus(aa, durationHint, cb, fd,
- clientId, callingPackageName, null, flags,
+ clientId, callingPackageName, flags,
sdk, false /*forceDuck*/, fakeUid, true /*permissionOverridesCheck*/);
}
diff --git a/services/core/java/com/android/server/audio/HardeningEnforcer.java b/services/core/java/com/android/server/audio/HardeningEnforcer.java
index 409ed17..8ae04ac 100644
--- a/services/core/java/com/android/server/audio/HardeningEnforcer.java
+++ b/services/core/java/com/android/server/audio/HardeningEnforcer.java
@@ -19,6 +19,7 @@
import android.Manifest;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.AppOpsManager;
import android.content.Context;
@@ -26,6 +27,7 @@
import android.media.AudioFocusRequest;
import android.media.AudioManager;
import android.os.Binder;
+import android.os.Build;
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.Slog;
@@ -128,19 +130,28 @@
* @param focusMethod name of the method to check, for logging purposes
* @param clientId id of the requester
* @param durationHint focus type being requested
+ * @param attributionTag attribution of the caller
+ * @param targetSdk target SDK of the caller
* @return false if the method call is allowed, true if it should be a no-op
*/
+ @SuppressWarnings("AndroidFrameworkCompatChange")
protected boolean blockFocusMethod(int callingUid, int focusMethod, @NonNull String clientId,
- int durationHint, @NonNull String packageName) {
+ int durationHint, @NonNull String packageName, String attributionTag, int targetSdk) {
if (packageName.isEmpty()) {
packageName = getPackNameForUid(callingUid);
}
- if (checkAppOp(AppOpsManager.OP_TAKE_AUDIO_FOCUS, callingUid, packageName)) {
+ if (noteOp(AppOpsManager.OP_TAKE_AUDIO_FOCUS, callingUid, packageName, attributionTag)) {
if (DEBUG) {
Slog.i(TAG, "blockFocusMethod pack:" + packageName + " NOT blocking");
}
return false;
+ } else if (targetSdk < Build.VERSION_CODES.VANILLA_ICE_CREAM) {
+ if (DEBUG) {
+ Slog.i(TAG, "blockFocusMethod pack:" + packageName + " NOT blocking due to sdk="
+ + targetSdk);
+ }
+ return false;
}
String errorMssg = "Focus request DENIED for uid:" + callingUid
@@ -169,14 +180,17 @@
}
/**
- * Checks the given op without throwing
+ * Notes the given op without throwing
* @param op the appOp code
* @param uid the calling uid
* @param packageName the package name of the caller
+ * @param attributionTag attribution of the caller
* @return return false if the operation is not allowed
*/
- private boolean checkAppOp(int op, int uid, @NonNull String packageName) {
- if (mAppOps.checkOpNoThrow(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) {
+ private boolean noteOp(int op, int uid, @NonNull String packageName,
+ @Nullable String attributionTag) {
+ if (mAppOps.noteOpNoThrow(op, uid, packageName, attributionTag, null)
+ != AppOpsManager.MODE_ALLOWED) {
return false;
}
return true;
diff --git a/services/core/java/com/android/server/audio/MediaFocusControl.java b/services/core/java/com/android/server/audio/MediaFocusControl.java
index 35d38e2..70f3193 100644
--- a/services/core/java/com/android/server/audio/MediaFocusControl.java
+++ b/services/core/java/com/android/server/audio/MediaFocusControl.java
@@ -1082,7 +1082,6 @@
* @param fd
* @param clientId
* @param callingPackageName
- * @param attributionTag
* @param flags
* @param sdk
* @param forceDuck only true if
@@ -1096,7 +1095,7 @@
*/
protected int requestAudioFocus(@NonNull AudioAttributes aa, int focusChangeHint, IBinder cb,
IAudioFocusDispatcher fd, @NonNull String clientId, @NonNull String callingPackageName,
- String attributionTag, int flags, int sdk, boolean forceDuck, int testUid,
+ int flags, int sdk, boolean forceDuck, int testUid,
boolean permissionOverridesCheck) {
new MediaMetrics.Item(mMetricsId)
.setUid(Binder.getCallingUid())
@@ -1129,12 +1128,6 @@
return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
}
- final int res = mAppOps.noteOp(AppOpsManager.OP_TAKE_AUDIO_FOCUS, Binder.getCallingUid(),
- callingPackageName, attributionTag, null);
- if (!permissionOverridesCheck && res != AppOpsManager.MODE_ALLOWED) {
- return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
- }
-
synchronized(mAudioFocusLock) {
// check whether a focus freeze is in place and filter
if (isFocusFrozenForTest()) {
diff --git a/services/core/java/com/android/server/broadcastradio/IRadioServiceAidlImpl.java b/services/core/java/com/android/server/broadcastradio/IRadioServiceAidlImpl.java
index e6de14b..16514fa 100644
--- a/services/core/java/com/android/server/broadcastradio/IRadioServiceAidlImpl.java
+++ b/services/core/java/com/android/server/broadcastradio/IRadioServiceAidlImpl.java
@@ -29,6 +29,7 @@
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.util.IndentingPrintWriter;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
@@ -121,8 +122,7 @@
+ " without permission " + Manifest.permission.DUMP);
return;
}
- android.util.IndentingPrintWriter radioPrintWriter =
- new android.util.IndentingPrintWriter(printWriter);
+ IndentingPrintWriter radioPrintWriter = new IndentingPrintWriter(printWriter);
radioPrintWriter.printf("BroadcastRadioService\n");
radioPrintWriter.increaseIndent();
diff --git a/services/core/java/com/android/server/broadcastradio/IRadioServiceHidlImpl.java b/services/core/java/com/android/server/broadcastradio/IRadioServiceHidlImpl.java
index 93fb7b2..ab08342 100644
--- a/services/core/java/com/android/server/broadcastradio/IRadioServiceHidlImpl.java
+++ b/services/core/java/com/android/server/broadcastradio/IRadioServiceHidlImpl.java
@@ -26,6 +26,7 @@
import android.hardware.radio.RadioManager;
import android.os.Binder;
import android.os.RemoteException;
+import android.util.IndentingPrintWriter;
import android.util.Log;
import android.util.Slog;
@@ -138,7 +139,7 @@
+ " without permission " + Manifest.permission.DUMP);
return;
}
- android.util.IndentingPrintWriter radioPw = new android.util.IndentingPrintWriter(pw);
+ IndentingPrintWriter radioPw = new IndentingPrintWriter(pw);
radioPw.printf("BroadcastRadioService\n");
radioPw.increaseIndent();
diff --git a/services/core/java/com/android/server/broadcastradio/RadioEventLogger.java b/services/core/java/com/android/server/broadcastradio/RadioEventLogger.java
index 2c8f499..b71589c 100644
--- a/services/core/java/com/android/server/broadcastradio/RadioEventLogger.java
+++ b/services/core/java/com/android/server/broadcastradio/RadioEventLogger.java
@@ -17,6 +17,7 @@
package com.android.server.broadcastradio;
import android.text.TextUtils;
+import android.util.IndentingPrintWriter;
import android.util.LocalLog;
import android.util.Log;
@@ -54,7 +55,7 @@
* Dump broadcast radio service event
* @param pw Indenting print writer for dump
*/
- public void dump(android.util.IndentingPrintWriter pw) {
+ public void dump(IndentingPrintWriter pw) {
mEventLogger.dump(pw);
}
}
diff --git a/services/core/java/com/android/server/broadcastradio/aidl/AnnouncementAggregator.java b/services/core/java/com/android/server/broadcastradio/aidl/AnnouncementAggregator.java
index 9654a93..b618aa3 100644
--- a/services/core/java/com/android/server/broadcastradio/aidl/AnnouncementAggregator.java
+++ b/services/core/java/com/android/server/broadcastradio/aidl/AnnouncementAggregator.java
@@ -22,6 +22,7 @@
import android.hardware.radio.ICloseHandle;
import android.os.IBinder;
import android.os.RemoteException;
+import android.util.IndentingPrintWriter;
import android.util.Log;
import com.android.internal.annotations.GuardedBy;
@@ -93,7 +94,7 @@
if (mCloseHandle != null) mCloseHandle.close();
}
- public void dumpInfo(android.util.IndentingPrintWriter pw) {
+ public void dumpInfo(IndentingPrintWriter pw) {
pw.printf("ModuleWatcher:\n");
pw.increaseIndent();
@@ -191,8 +192,7 @@
@Override
protected void dump(FileDescriptor fd, PrintWriter printWriter, String[] args) {
- android.util.IndentingPrintWriter announcementPrintWriter =
- new android.util.IndentingPrintWriter(printWriter);
+ IndentingPrintWriter announcementPrintWriter = new IndentingPrintWriter(printWriter);
announcementPrintWriter.printf("AnnouncementAggregator\n");
announcementPrintWriter.increaseIndent();
diff --git a/services/core/java/com/android/server/broadcastradio/aidl/BroadcastRadioServiceImpl.java b/services/core/java/com/android/server/broadcastradio/aidl/BroadcastRadioServiceImpl.java
index 1c42161..d9f8588 100644
--- a/services/core/java/com/android/server/broadcastradio/aidl/BroadcastRadioServiceImpl.java
+++ b/services/core/java/com/android/server/broadcastradio/aidl/BroadcastRadioServiceImpl.java
@@ -29,6 +29,7 @@
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.ArrayMap;
+import android.util.IndentingPrintWriter;
import android.util.Log;
import android.util.SparseArray;
@@ -128,7 +129,7 @@
if (entry.getValue() == mModuleId) {
Slogf.w(TAG, "Service %s died, removed RadioModule with ID %d",
entry.getKey(), mModuleId);
- return;
+ break;
}
}
}
@@ -260,7 +261,7 @@
*
* @param pw The file to which {@link BroadcastRadioServiceImpl} state is dumped.
*/
- public void dumpInfo(android.util.IndentingPrintWriter pw) {
+ public void dumpInfo(IndentingPrintWriter pw) {
synchronized (mLock) {
pw.printf("Next module id available: %d\n", mNextModuleId);
pw.printf("ServiceName to module id map:\n");
diff --git a/services/core/java/com/android/server/broadcastradio/aidl/ConversionUtils.java b/services/core/java/com/android/server/broadcastradio/aidl/ConversionUtils.java
index 5b77c52..077e8ee 100644
--- a/services/core/java/com/android/server/broadcastradio/aidl/ConversionUtils.java
+++ b/services/core/java/com/android/server/broadcastradio/aidl/ConversionUtils.java
@@ -446,6 +446,7 @@
sel.secondaryIds[i]);
if (id == null) {
Slogf.e(TAG, "invalid secondary id: %s", sel.secondaryIds[i]);
+ continue;
}
secondaryIdList.add(id);
}
diff --git a/services/core/java/com/android/server/broadcastradio/aidl/RadioModule.java b/services/core/java/com/android/server/broadcastradio/aidl/RadioModule.java
index 0cac356..03e347a 100644
--- a/services/core/java/com/android/server/broadcastradio/aidl/RadioModule.java
+++ b/services/core/java/com/android/server/broadcastradio/aidl/RadioModule.java
@@ -38,6 +38,7 @@
import android.os.RemoteException;
import android.os.UserHandle;
import android.util.ArraySet;
+import android.util.IndentingPrintWriter;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
@@ -524,7 +525,7 @@
return BitmapFactory.decodeByteArray(rawImage, 0, rawImage.length);
}
- void dumpInfo(android.util.IndentingPrintWriter pw) {
+ void dumpInfo(IndentingPrintWriter pw) {
pw.printf("RadioModule\n");
pw.increaseIndent();
diff --git a/services/core/java/com/android/server/broadcastradio/aidl/TunerSession.java b/services/core/java/com/android/server/broadcastradio/aidl/TunerSession.java
index 925f149..e90a1dd 100644
--- a/services/core/java/com/android/server/broadcastradio/aidl/TunerSession.java
+++ b/services/core/java/com/android/server/broadcastradio/aidl/TunerSession.java
@@ -29,6 +29,7 @@
import android.os.RemoteException;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.IndentingPrintWriter;
import com.android.internal.annotations.GuardedBy;
import com.android.server.broadcastradio.RadioEventLogger;
@@ -434,7 +435,7 @@
}
}
- void dumpInfo(android.util.IndentingPrintWriter pw) {
+ void dumpInfo(IndentingPrintWriter pw) {
pw.printf("TunerSession\n");
pw.increaseIndent();
diff --git a/services/core/java/com/android/server/broadcastradio/hal2/BroadcastRadioService.java b/services/core/java/com/android/server/broadcastradio/hal2/BroadcastRadioService.java
index e1650c2..a4efa2e 100644
--- a/services/core/java/com/android/server/broadcastradio/hal2/BroadcastRadioService.java
+++ b/services/core/java/com/android/server/broadcastradio/hal2/BroadcastRadioService.java
@@ -30,6 +30,7 @@
import android.os.IHwBinder.DeathRecipient;
import android.os.RemoteException;
import android.util.ArrayMap;
+import android.util.IndentingPrintWriter;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
@@ -115,7 +116,7 @@
if (entry.getValue() == moduleId) {
Slogf.i(TAG, "service " + entry.getKey()
+ " died; removed RadioModule with ID " + moduleId);
- return;
+ break;
}
}
}
@@ -221,7 +222,7 @@
*
* @param pw The file to which BroadcastRadioService state is dumped.
*/
- public void dumpInfo(android.util.IndentingPrintWriter pw) {
+ public void dumpInfo(IndentingPrintWriter pw) {
synchronized (mLock) {
pw.printf("Next module id available: %d\n", mNextModuleId);
pw.printf("ServiceName to module id map:\n");
diff --git a/services/core/java/com/android/server/broadcastradio/hal2/Convert.java b/services/core/java/com/android/server/broadcastradio/hal2/Convert.java
index 34bfa6c..02a9f09 100644
--- a/services/core/java/com/android/server/broadcastradio/hal2/Convert.java
+++ b/services/core/java/com/android/server/broadcastradio/hal2/Convert.java
@@ -304,10 +304,7 @@
private static boolean isEmpty(
@NonNull android.hardware.broadcastradio.V2_0.ProgramSelector sel) {
- if (sel.primaryId.type != 0) return false;
- if (sel.primaryId.value != 0) return false;
- if (!sel.secondaryIds.isEmpty()) return false;
- return true;
+ return sel.primaryId.type == 0 && sel.primaryId.value == 0 && sel.secondaryIds.isEmpty();
}
static @Nullable ProgramSelector programSelectorFromHal(
diff --git a/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java b/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java
index 7269f24..d3b2448 100644
--- a/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java
+++ b/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java
@@ -40,6 +40,7 @@
import android.os.RemoteException;
import android.os.UserHandle;
import android.util.ArraySet;
+import android.util.IndentingPrintWriter;
import android.util.MutableInt;
import com.android.internal.annotations.GuardedBy;
@@ -453,7 +454,7 @@
return BitmapFactory.decodeByteArray(rawImage, 0, rawImage.length);
}
- void dumpInfo(android.util.IndentingPrintWriter pw) {
+ void dumpInfo(IndentingPrintWriter pw) {
pw.printf("RadioModule\n");
pw.increaseIndent();
pw.printf("BroadcastRadioService: %s\n", mService);
diff --git a/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java b/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java
index b1b5d34..80efacd 100644
--- a/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java
+++ b/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java
@@ -31,6 +31,7 @@
import android.os.RemoteException;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.IndentingPrintWriter;
import android.util.MutableBoolean;
import android.util.MutableInt;
@@ -324,9 +325,7 @@
try {
isConfigFlagSet(flag);
return true;
- } catch (IllegalStateException ex) {
- return true;
- } catch (UnsupportedOperationException ex) {
+ } catch (IllegalStateException | UnsupportedOperationException ex) {
return false;
}
}
@@ -389,7 +388,7 @@
}
}
- void dumpInfo(android.util.IndentingPrintWriter pw) {
+ void dumpInfo(IndentingPrintWriter pw) {
pw.printf("TunerSession\n");
pw.increaseIndent();
pw.printf("HIDL HAL Session: %s\n", mHwSession);
diff --git a/services/core/java/com/android/server/display/DisplayDeviceInfo.java b/services/core/java/com/android/server/display/DisplayDeviceInfo.java
index b1b1dba..93bd926 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceInfo.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceInfo.java
@@ -212,24 +212,46 @@
public static final int TOUCH_VIRTUAL = 3;
/**
- * Diff result: The {@link #state} or {@link #committedState} fields differ.
- */
- public static final int DIFF_STATE = 1 << 0;
-
- /**
* Diff result: Other fields differ.
*/
- public static final int DIFF_OTHER = 1 << 1;
+ public static final int DIFF_OTHER = 1 << 0;
+
+ /**
+ * Diff result: The {@link #state} or {@link #committedState} fields differ.
+ */
+ public static final int DIFF_STATE = 1 << 1;
+
+ /**
+ * Diff result: The committed state differs. Note this is slightly different from the state,
+ * which is what most of the device should care about.
+ */
+ public static final int DIFF_COMMITTED_STATE = 1 << 2;
/**
* Diff result: The color mode fields differ.
*/
- public static final int DIFF_COLOR_MODE = 1 << 2;
+ public static final int DIFF_COLOR_MODE = 1 << 3;
/**
* Diff result: The hdr/sdr ratio differs
*/
- public static final int DIFF_HDR_SDR_RATIO = 1 << 3;
+ public static final int DIFF_HDR_SDR_RATIO = 1 << 4;
+
+ /**
+ * Diff result: The rotation differs
+ */
+ public static final int DIFF_ROTATION = 1 << 5;
+
+ /**
+ * Diff result: The render timings. Note this could be any of {@link #renderFrameRate},
+ * {@link #presentationDeadlineNanos}, or {@link #appVsyncOffsetNanos}.
+ */
+ public static final int DIFF_RENDER_TIMINGS = 1 << 6;
+
+ /**
+ * Diff result: The mode ID differs.
+ */
+ public static final int DIFF_MODE_ID = 1 << 7;
/**
* Diff result: Catch-all for "everything changed"
@@ -462,21 +484,33 @@
*/
public int diff(DisplayDeviceInfo other) {
int diff = 0;
- if (state != other.state || committedState != other.committedState) {
+ if (state != other.state) {
diff |= DIFF_STATE;
}
+ if (committedState != other.committedState) {
+ diff |= DIFF_COMMITTED_STATE;
+ }
if (colorMode != other.colorMode) {
diff |= DIFF_COLOR_MODE;
}
if (!BrightnessSynchronizer.floatEquals(hdrSdrRatio, other.hdrSdrRatio)) {
diff |= DIFF_HDR_SDR_RATIO;
}
+ if (rotation != other.rotation) {
+ diff |= DIFF_ROTATION;
+ }
+ if (renderFrameRate != other.renderFrameRate
+ || presentationDeadlineNanos != other.presentationDeadlineNanos
+ || appVsyncOffsetNanos != other.appVsyncOffsetNanos) {
+ diff |= DIFF_RENDER_TIMINGS;
+ }
+ if (modeId != other.modeId) {
+ diff |= DIFF_MODE_ID;
+ }
if (!Objects.equals(name, other.name)
|| !Objects.equals(uniqueId, other.uniqueId)
|| width != other.width
|| height != other.height
- || modeId != other.modeId
- || renderFrameRate != other.renderFrameRate
|| defaultModeId != other.defaultModeId
|| userPreferredModeId != other.userPreferredModeId
|| !Arrays.equals(supportedModes, other.supportedModes)
@@ -487,12 +521,9 @@
|| densityDpi != other.densityDpi
|| xDpi != other.xDpi
|| yDpi != other.yDpi
- || appVsyncOffsetNanos != other.appVsyncOffsetNanos
- || presentationDeadlineNanos != other.presentationDeadlineNanos
|| flags != other.flags
|| !Objects.equals(displayCutout, other.displayCutout)
|| touch != other.touch
- || rotation != other.rotation
|| type != other.type
|| !Objects.equals(address, other.address)
|| !Objects.equals(deviceProductInfo, other.deviceProductInfo)
diff --git a/services/core/java/com/android/server/display/DisplayDeviceRepository.java b/services/core/java/com/android/server/display/DisplayDeviceRepository.java
index 6164154..086f8a9 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceRepository.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceRepository.java
@@ -21,6 +21,7 @@
import android.util.Slog;
import android.view.Display;
import android.view.DisplayAddress;
+import android.view.Surface;
import com.android.internal.annotations.GuardedBy;
import com.android.server.display.DisplayManagerService.SyncRoot;
@@ -179,6 +180,20 @@
if (diff == DisplayDeviceInfo.DIFF_STATE) {
Slog.i(TAG, "Display device changed state: \"" + info.name
+ "\", " + Display.stateToString(info.state));
+ } else if (diff == DisplayDeviceInfo.DIFF_ROTATION) {
+ Slog.i(TAG, "Display device rotated: \"" + info.name
+ + "\", " + Surface.rotationToString(info.rotation));
+ } else if (diff
+ == (DisplayDeviceInfo.DIFF_MODE_ID | DisplayDeviceInfo.DIFF_RENDER_TIMINGS)) {
+ Slog.i(TAG, "Display device changed render timings: \"" + info.name
+ + "\", renderFrameRate=" + info.renderFrameRate
+ + ", presentationDeadlineNanos=" + info.presentationDeadlineNanos
+ + ", appVsyncOffsetNanos=" + info.appVsyncOffsetNanos);
+ } else if (diff == DisplayDeviceInfo.DIFF_COMMITTED_STATE) {
+ if (DEBUG) {
+ Slog.i(TAG, "Display device changed committed state: \"" + info.name
+ + "\", " + Display.stateToString(info.committedState));
+ }
} else if (diff != DisplayDeviceInfo.DIFF_HDR_SDR_RATIO) {
Slog.i(TAG, "Display device changed: " + info);
}
diff --git a/services/core/java/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy.java b/services/core/java/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy.java
index 2b5241f..b43b35b 100644
--- a/services/core/java/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy.java
+++ b/services/core/java/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy.java
@@ -102,6 +102,9 @@
private DisplayManagerFlags mDisplayManagerFlags;
+ // Indicates if the current auto-brightness should be ramped up or down slowly.
+ private boolean mIsSlowChange;
+
@VisibleForTesting
AutomaticBrightnessStrategy(Context context, int displayId, Injector injector,
DisplayManagerFlags displayManagerFlags) {
@@ -172,6 +175,11 @@
isValid = true;
}
}
+
+ // A change is slow when the auto-brightness was already applied, and there are no new
+ // auto-brightness adjustments from an external client(e.g. Moving the slider). As such,
+ // it is important to record this value before applying the current auto-brightness.
+ mIsSlowChange = hasAppliedAutoBrightness() && !getAutoBrightnessAdjustmentChanged();
setAutoBrightnessApplied(isValid);
return isValid;
}
@@ -284,8 +292,7 @@
.setSdrBrightness(brightness)
.setBrightnessReason(brightnessReason)
.setDisplayBrightnessStrategyName(getName())
- .setIsSlowChange(hasAppliedAutoBrightness()
- && !getAutoBrightnessAdjustmentChanged())
+ .setIsSlowChange(mIsSlowChange)
.setBrightnessEvent(brightnessEvent)
.setBrightnessAdjustmentFlag(mAutoBrightnessAdjustmentReasonsFlags)
.setShouldUpdateScreenBrightnessSetting(
diff --git a/services/core/java/com/android/server/hdmi/DeviceDiscoveryAction.java b/services/core/java/com/android/server/hdmi/DeviceDiscoveryAction.java
old mode 100755
new mode 100644
diff --git a/services/core/java/com/android/server/health/HealthServiceWrapperAidl.java b/services/core/java/com/android/server/health/HealthServiceWrapperAidl.java
index 8a3a56c..fd3a92e 100644
--- a/services/core/java/com/android/server/health/HealthServiceWrapperAidl.java
+++ b/services/core/java/com/android/server/health/HealthServiceWrapperAidl.java
@@ -212,6 +212,16 @@
}
}
+ public void setChargingPolicy(int policy) throws RemoteException {
+ IHealth service = mLastService.get();
+ if (service == null) return;
+ try {
+ service.setChargingPolicy(policy);
+ } catch (UnsupportedOperationException | ServiceSpecificException ex) {
+ return;
+ }
+ }
+
private static void traceBegin(String name) {
Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, name);
}
diff --git a/services/core/java/com/android/server/health/OWNERS b/services/core/java/com/android/server/health/OWNERS
index 81522fc..44ab7f7 100644
--- a/services/core/java/com/android/server/health/OWNERS
+++ b/services/core/java/com/android/server/health/OWNERS
@@ -1 +1 @@
-file:platform/hardware/interfaces:/health/aidl/OWNERS
+file:platform/hardware/interfaces:/health/OWNERS
diff --git a/services/core/java/com/android/server/inputmethod/DefaultImeVisibilityApplier.java b/services/core/java/com/android/server/inputmethod/DefaultImeVisibilityApplier.java
index 2e44b6d..7d48527 100644
--- a/services/core/java/com/android/server/inputmethod/DefaultImeVisibilityApplier.java
+++ b/services/core/java/com/android/server/inputmethod/DefaultImeVisibilityApplier.java
@@ -32,6 +32,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.UserIdInt;
import android.os.IBinder;
import android.os.ResultReceiver;
import android.util.EventLog;
@@ -137,15 +138,17 @@
@GuardedBy("ImfLock.class")
@Override
public void applyImeVisibility(IBinder windowToken, @NonNull ImeTracker.Token statsToken,
- @ImeVisibilityStateComputer.VisibilityState int state) {
+ @ImeVisibilityStateComputer.VisibilityState int state, @UserIdInt int userId) {
applyImeVisibility(windowToken, statsToken, state,
- SoftInputShowHideReason.NOT_SET /* ignore reason */);
+ SoftInputShowHideReason.NOT_SET /* ignore reason */, userId);
}
@GuardedBy("ImfLock.class")
void applyImeVisibility(IBinder windowToken, @Nullable ImeTracker.Token statsToken,
@ImeVisibilityStateComputer.VisibilityState int state,
- @SoftInputShowHideReason int reason) {
+ @SoftInputShowHideReason int reason, @UserIdInt int userId) {
+ final var bindingController = mService.getInputMethodBindingController(userId);
+ final int displayIdToShowIme = bindingController.getDisplayIdToShowIme();
switch (state) {
case STATE_SHOW_IME:
if (!Flags.refactorInsetsController()) {
@@ -165,8 +168,7 @@
// NOT_FOCUSABLE, ALT_FOCUSABLE_IM flags set and can the IME target.
// Send it to window manager to hide IME from the actual IME control target
// of the target display.
- mWindowManagerInternal.hideIme(windowToken,
- mService.getDisplayIdToShowImeLocked(), statsToken);
+ mWindowManagerInternal.hideIme(windowToken, displayIdToShowIme, statsToken);
} else {
ImeTracker.forLogging().onFailed(statsToken,
ImeTracker.PHASE_SERVER_APPLY_IME_VISIBILITY);
@@ -201,10 +203,10 @@
}
break;
case STATE_SHOW_IME_SNAPSHOT:
- showImeScreenshot(windowToken, mService.getDisplayIdToShowImeLocked());
+ showImeScreenshot(windowToken, displayIdToShowIme);
break;
case STATE_REMOVE_IME_SNAPSHOT:
- removeImeScreenshot(mService.getDisplayIdToShowImeLocked());
+ removeImeScreenshot(displayIdToShowIme);
break;
default:
throw new IllegalArgumentException("Invalid IME visibility state: " + state);
diff --git a/services/core/java/com/android/server/inputmethod/ImeVisibilityApplier.java b/services/core/java/com/android/server/inputmethod/ImeVisibilityApplier.java
index 9f2b84d..a5f9b7a 100644
--- a/services/core/java/com/android/server/inputmethod/ImeVisibilityApplier.java
+++ b/services/core/java/com/android/server/inputmethod/ImeVisibilityApplier.java
@@ -17,6 +17,7 @@
package com.android.server.inputmethod;
import android.annotation.NonNull;
+import android.annotation.UserIdInt;
import android.os.IBinder;
import android.os.ResultReceiver;
import android.view.inputmethod.ImeTracker;
@@ -63,7 +64,7 @@
* @param state The new IME visibility state for the applier to handle
*/
default void applyImeVisibility(IBinder windowToken, @NonNull ImeTracker.Token statsToken,
- @ImeVisibilityStateComputer.VisibilityState int state) {}
+ @ImeVisibilityStateComputer.VisibilityState int state, @UserIdInt int userId) {}
/**
* Updates the IME Z-ordering relative to the given window.
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
index 8191ee1..3d75c48 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
@@ -18,6 +18,7 @@
import static android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_DENIED;
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
+import static android.view.Display.INVALID_DISPLAY;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -82,12 +83,15 @@
@GuardedBy("ImfLock.class") @Nullable private IInputMethodInvoker mCurMethod;
@GuardedBy("ImfLock.class") private int mCurMethodUid = Process.INVALID_UID;
@GuardedBy("ImfLock.class") @Nullable private IBinder mCurToken;
- @GuardedBy("ImfLock.class") private int mCurTokenDisplayId = Display.INVALID_DISPLAY;
+ @GuardedBy("ImfLock.class") private int mCurTokenDisplayId = INVALID_DISPLAY;
@GuardedBy("ImfLock.class") private int mCurSeq;
@GuardedBy("ImfLock.class") private boolean mVisibleBound;
@GuardedBy("ImfLock.class") private boolean mSupportsStylusHw;
@GuardedBy("ImfLock.class") private boolean mSupportsConnectionlessStylusHw;
+ /** The display id for which the latest startInput was called. */
+ @GuardedBy("ImfLock.class") private int mDisplayIdToShowIme = INVALID_DISPLAY;
+
@Nullable private CountDownLatch mLatchForTesting;
/**
@@ -455,7 +459,7 @@
mWindowManagerInternal.removeWindowToken(mCurToken, true /* removeWindows */,
false /* animateExit */, mCurTokenDisplayId);
mCurToken = null;
- mCurTokenDisplayId = Display.INVALID_DISPLAY;
+ mCurTokenDisplayId = INVALID_DISPLAY;
}
@GuardedBy("ImfLock.class")
@@ -478,16 +482,15 @@
mCurId = info.getId();
mLastBindTime = SystemClock.uptimeMillis();
- final int displayIdToShowIme = mService.getDisplayIdToShowImeLocked();
mCurToken = new Binder();
- mCurTokenDisplayId = displayIdToShowIme;
+ mCurTokenDisplayId = mDisplayIdToShowIme;
if (DEBUG) {
Slog.v(TAG, "Adding window token: " + mCurToken + " for display: "
- + displayIdToShowIme);
+ + mDisplayIdToShowIme);
}
mWindowManagerInternal.addWindowToken(mCurToken,
WindowManager.LayoutParams.TYPE_INPUT_METHOD,
- displayIdToShowIme, null /* options */);
+ mDisplayIdToShowIme, null /* options */);
return new InputBindResult(
InputBindResult.ResultCode.SUCCESS_WAITING_IME_BINDING,
null, null, null, mCurId, mCurSeq, false);
@@ -596,4 +599,14 @@
unbindVisibleConnection();
}
}
+
+ @GuardedBy("ImfLock.class")
+ void setDisplayIdToShowIme(int displayId) {
+ mDisplayIdToShowIme = displayId;
+ }
+
+ @GuardedBy("ImfLock.class")
+ int getDisplayIdToShowIme() {
+ return mDisplayIdToShowIme;
+ }
}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 8665a39..d236d7a 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -227,6 +227,16 @@
}
/**
+ * Indicates that the annotated field is shared by all the users.
+ *
+ * <p>See b/305849394 for details.</p>
+ */
+ @Retention(SOURCE)
+ @Target({ElementType.FIELD})
+ private @interface SharedByAllUsersField {
+ }
+
+ /**
* Indicates that the annotated field is not yet ready for concurrent multi-user support.
*
* <p>See b/305849394 for details.</p>
@@ -272,6 +282,7 @@
* {@link LayoutParams#SOFT_INPUT_STATE_ALWAYS_VISIBLE SOFT_INPUT_STATE_ALWAYS_VISIBLE}
* starting from {@link android.os.Build.VERSION_CODES#P}.
*/
+ @SharedByAllUsersField
private final boolean mPreventImeStartupUnlessTextEditor;
/**
@@ -279,6 +290,7 @@
* from the IME startup avoidance behavior that is enabled by
* {@link #mPreventImeStartupUnlessTextEditor}.
*/
+ @SharedByAllUsersField
@NonNull
private final String[] mNonPreemptibleInputMethods;
@@ -286,6 +298,7 @@
* See {@link #shouldEnableExperimentalConcurrentMultiUserMode(Context)} about when set to be
* {@code true}.
*/
+ @SharedByAllUsersField
private final boolean mExperimentalConcurrentMultiUserModeEnabled;
/**
@@ -327,6 +340,7 @@
final PackageManagerInternal mPackageManagerInternal;
final InputManagerInternal mInputManagerInternal;
final ImePlatformCompatUtils mImePlatformCompatUtils;
+ @SharedByAllUsersField
final InputMethodDeviceConfigs mInputMethodDeviceConfigs;
private final UserManagerInternal mUserManagerInternal;
@@ -339,6 +353,7 @@
private final ImeVisibilityStateComputer mVisibilityStateComputer;
@GuardedBy("ImfLock.class")
+ @SharedByAllUsersField
@NonNull
private final DefaultImeVisibilityApplier mVisibilityApplier;
@@ -355,7 +370,7 @@
// Mapping from deviceId to the device-specific imeId for that device.
@GuardedBy("ImfLock.class")
- @MultiUserUnawareField
+ @SharedByAllUsersField
private final SparseArray<String> mVirtualDeviceMethodMap = new SparseArray<>();
// TODO: Instantiate mSwitchingController for each user.
@@ -367,36 +382,19 @@
@MultiUserUnawareField
private HardwareKeyboardShortcutController mHardwareKeyboardShortcutController;
- /**
- * Tracks how many times {@link #mSettings} was updated.
- */
- @GuardedBy("ImfLock.class")
- private int mMethodMapUpdateCount = 0;
-
- /**
- * The display id for which the latest startInput was called.
- */
- @GuardedBy("ImfLock.class")
- int getDisplayIdToShowImeLocked() {
- return mDisplayIdToShowIme;
- }
-
- @GuardedBy("ImfLock.class")
- @MultiUserUnawareField
- private int mDisplayIdToShowIme = INVALID_DISPLAY;
-
@GuardedBy("ImfLock.class")
@MultiUserUnawareField
private int mDeviceIdToShowIme = DEVICE_ID_DEFAULT;
@Nullable
private StatusBarManagerInternal mStatusBarManagerInternal;
+ @SharedByAllUsersField
private boolean mShowOngoingImeSwitcherForPhones;
@GuardedBy("ImfLock.class")
@MultiUserUnawareField
private final HandwritingModeController mHwController;
@GuardedBy("ImfLock.class")
- @MultiUserUnawareField
+ @SharedByAllUsersField
private IntArray mStylusIds;
@GuardedBy("ImfLock.class")
@@ -475,6 +473,7 @@
/**
* Manages the IME clients.
*/
+ @SharedByAllUsersField
private final ClientController mClientController;
/**
@@ -486,6 +485,7 @@
/**
* Set once the system is ready to run third party code.
*/
+ @SharedByAllUsersField
boolean mSystemReady;
@GuardedBy("ImfLock.class")
@@ -522,6 +522,7 @@
/**
* The client that is currently bound to an input method.
*/
+ @MultiUserUnawareField
@Nullable
private ClientState mCurClient;
@@ -573,6 +574,7 @@
* {@link android.view.InsetsController} for the given window.
*/
@GuardedBy("ImfLock.class")
+ @SharedByAllUsersField
private final WeakHashMap<IBinder, Boolean> mFocusedWindowPerceptible = new WeakHashMap<>();
/**
@@ -677,28 +679,36 @@
@MultiUserUnawareField
int mImeWindowVis;
+ @SharedByAllUsersField
private final MyPackageMonitor mMyPackageMonitor = new MyPackageMonitor();
+
+ @SharedByAllUsersField
private final String mSlotIme;
/**
* Registered {@link InputMethodListListener}.
* This variable can be accessed from both of MainThread and BinderThread.
*/
+ @SharedByAllUsersField
private final CopyOnWriteArrayList<InputMethodListListener> mInputMethodListListeners =
new CopyOnWriteArrayList<>();
@GuardedBy("ImfLock.class")
+ @SharedByAllUsersField
private final WeakHashMap<IBinder, IBinder> mImeTargetWindowMap = new WeakHashMap<>();
@GuardedBy("ImfLock.class")
+ @SharedByAllUsersField
@NonNull
private final StartInputHistory mStartInputHistory = new StartInputHistory();
@GuardedBy("ImfLock.class")
+ @SharedByAllUsersField
@NonNull
private final SoftInputShowHideHistory mSoftInputShowHideHistory =
new SoftInputShowHideHistory();
+ @SharedByAllUsersField
@NonNull
private final ImeTrackerService mImeTrackerService;
@@ -1951,7 +1961,7 @@
final var statsToken = createStatsTokenForFocusedClient(false /* show */,
SoftInputShowHideReason.UNBIND_CURRENT_METHOD);
mVisibilityApplier.applyImeVisibility(mImeBindingState.mFocusedWindow, statsToken,
- STATE_HIDE_IME);
+ STATE_HIDE_IME, mCurrentUserId);
}
}
@@ -2122,7 +2132,8 @@
return InputBindResult.NOT_IME_TARGET_WINDOW;
}
final int csDisplayId = cs.mSelfReportedDisplayId;
- mDisplayIdToShowIme = mVisibilityStateComputer.computeImeDisplayId(winState, csDisplayId);
+ bindingController.setDisplayIdToShowIme(
+ mVisibilityStateComputer.computeImeDisplayId(winState, csDisplayId));
// Potentially override the selected input method if the new display belongs to a virtual
// device with a custom IME.
@@ -2193,8 +2204,9 @@
// We expect the caller has already verified that the client is allowed to access this
// display ID.
final String curId = bindingController.getCurId();
+ final int displayIdToShowIme = bindingController.getDisplayIdToShowIme();
if (curId != null && curId.equals(bindingController.getSelectedMethodId())
- && mDisplayIdToShowIme == getCurTokenDisplayIdLocked()) {
+ && displayIdToShowIme == getCurTokenDisplayIdLocked()) {
if (cs.mCurSession != null) {
// Fast case: if we are already connected to the input method,
// then just return it.
@@ -2245,7 +2257,9 @@
final InputMethodSettings settings = InputMethodSettingsRepository.get(userId);
final int oldDeviceId = mDeviceIdToShowIme;
- mDeviceIdToShowIme = mVdmInternal.getDeviceIdForDisplayId(mDisplayIdToShowIme);
+ final var bindingController = getInputMethodBindingController(userId);
+ final int displayIdToShowIme = bindingController.getDisplayIdToShowIme();
+ mDeviceIdToShowIme = mVdmInternal.getDeviceIdForDisplayId(displayIdToShowIme);
if (mDeviceIdToShowIme == DEVICE_ID_DEFAULT) {
if (oldDeviceId == DEVICE_ID_DEFAULT) {
return currentMethodId;
@@ -2279,7 +2293,7 @@
if (DEBUG) {
Slog.v(TAG, "Switching current input method from " + currentMethodId
+ " to device-specific one " + deviceMethodId + " because the current display "
- + mDisplayIdToShowIme + " belongs to device with id " + mDeviceIdToShowIme);
+ + displayIdToShowIme + " belongs to device with id " + mDeviceIdToShowIme);
}
return deviceMethodId;
}
@@ -2959,10 +2973,11 @@
@GuardedBy("ImfLock.class")
void updateInputMethodsFromSettingsLocked(boolean enabledMayChange) {
- final InputMethodSettings settings = InputMethodSettingsRepository.get(mCurrentUserId);
+ final int userId = mCurrentUserId;
+ final InputMethodSettings settings = InputMethodSettingsRepository.get(userId);
if (enabledMayChange) {
final PackageManager userAwarePackageManager = getPackageManagerForUser(mContext,
- settings.getUserId());
+ userId);
List<InputMethodInfo> enabled = settings.getEnabledInputMethodList();
for (int i = 0; i < enabled.size(); i++) {
@@ -2991,20 +3006,19 @@
if (mDeviceIdToShowIme == DEVICE_ID_DEFAULT) {
String ime = SecureSettingsWrapper.getString(
- Settings.Secure.DEFAULT_INPUT_METHOD, null, settings.getUserId());
+ Settings.Secure.DEFAULT_INPUT_METHOD, null, userId);
String defaultDeviceIme = SecureSettingsWrapper.getString(
- Settings.Secure.DEFAULT_DEVICE_INPUT_METHOD, null, settings.getUserId());
+ Settings.Secure.DEFAULT_DEVICE_INPUT_METHOD, null, userId);
if (defaultDeviceIme != null && !Objects.equals(ime, defaultDeviceIme)) {
if (DEBUG) {
Slog.v(TAG, "Current input method " + ime + " differs from the stored default"
- + " device input method for user " + settings.getUserId()
+ + " device input method for user " + userId
+ " - restoring " + defaultDeviceIme);
}
SecureSettingsWrapper.putString(
- Settings.Secure.DEFAULT_INPUT_METHOD, defaultDeviceIme,
- settings.getUserId());
+ Settings.Secure.DEFAULT_INPUT_METHOD, defaultDeviceIme, userId);
SecureSettingsWrapper.putString(
- Settings.Secure.DEFAULT_DEVICE_INPUT_METHOD, null, settings.getUserId());
+ Settings.Secure.DEFAULT_DEVICE_INPUT_METHOD, null, userId);
}
}
@@ -3030,18 +3044,18 @@
}
// TODO: Instantiate mSwitchingController for each user.
- if (settings.getUserId() == mSwitchingController.getUserId()) {
+ if (userId == mSwitchingController.getUserId()) {
mSwitchingController.resetCircularListLocked(settings.getMethodMap());
} else {
mSwitchingController = InputMethodSubtypeSwitchingController.createInstanceLocked(
- mContext, settings.getMethodMap(), settings.getUserId());
+ mContext, settings.getMethodMap(), userId);
}
// TODO: Instantiate mHardwareKeyboardShortcutController for each user.
- if (settings.getUserId() == mHardwareKeyboardShortcutController.getUserId()) {
+ if (userId == mHardwareKeyboardShortcutController.getUserId()) {
mHardwareKeyboardShortcutController.reset(settings.getMethodMap());
} else {
mHardwareKeyboardShortcutController = new HardwareKeyboardShortcutController(
- settings.getMethodMap(), settings.getUserId());
+ settings.getMethodMap(), userId);
}
sendOnNavButtonFlagsChangedLocked();
}
@@ -3065,7 +3079,8 @@
@GuardedBy("ImfLock.class")
void setInputMethodLocked(String id, int subtypeId, int deviceId) {
- final InputMethodSettings settings = InputMethodSettingsRepository.get(mCurrentUserId);
+ final int userId = mCurrentUserId;
+ final InputMethodSettings settings = InputMethodSettingsRepository.get(userId);
InputMethodInfo info = settings.getMethodMap().get(id);
if (info == null) {
throw getExceptionForUnknownImeId(id);
@@ -3073,7 +3088,6 @@
// See if we need to notify a subtype change within the same IME.
if (id.equals(getSelectedMethodIdLocked())) {
- final int userId = settings.getUserId();
final int subtypeCount = info.getSubtypeCount();
if (subtypeCount <= 0) {
notifyInputMethodSubtypeChangedLocked(userId, info, null);
@@ -3129,7 +3143,7 @@
// mCurMethodId should be updated after setSelectedInputMethodAndSubtypeLocked()
// because mCurMethodId is stored as a history in
// setSelectedInputMethodAndSubtypeLocked().
- getInputMethodBindingController(mCurrentUserId).setSelectedMethodId(id);
+ getInputMethodBindingController(userId).setSelectedMethodId(id);
if (mActivityManagerInternal.isSystemReady()) {
Intent intent = new Intent(Intent.ACTION_INPUT_METHOD_CHANGED);
@@ -4653,7 +4667,7 @@
windowToken);
mVisibilityApplier.applyImeVisibility(requestToken, statsToken,
setVisible ? ImeVisibilityStateComputer.STATE_SHOW_IME
- : ImeVisibilityStateComputer.STATE_HIDE_IME);
+ : ImeVisibilityStateComputer.STATE_HIDE_IME, mCurrentUserId);
}
} finally {
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
@@ -5226,7 +5240,6 @@
Slog.e(TAG, "buildInputMethodListLocked is not allowed until system is ready");
return;
}
- mMethodMapUpdateCount++;
final InputMethodSettings settings = InputMethodSettingsRepository.get(mCurrentUserId);
@@ -5446,7 +5459,8 @@
@GuardedBy("ImfLock.class")
private void resetSelectedInputMethodAndSubtypeLocked(String newDefaultIme) {
mDeviceIdToShowIme = DEVICE_ID_DEFAULT;
- mDisplayIdToShowIme = INVALID_DISPLAY;
+ final var bindingController = getInputMethodBindingController(mCurrentUserId);
+ bindingController.setDisplayIdToShowIme(INVALID_DISPLAY);
final InputMethodSettings settings = InputMethodSettingsRepository.get(mCurrentUserId);
settings.putSelectedDefaultDeviceInputMethod(null);
@@ -6051,7 +6065,7 @@
p.println("Current Input Method Manager state:");
final List<InputMethodInfo> methodList = settings.getMethodList();
int numImes = methodList.size();
- p.println(" Input Methods: mMethodMapUpdateCount=" + mMethodMapUpdateCount);
+ p.println(" Input Methods:");
for (int i = 0; i < numImes; i++) {
InputMethodInfo info = methodList.get(i);
p.println(" InputMethod #" + i + ":");
diff --git a/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java b/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
index d5e85da..3673eb0 100644
--- a/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
+++ b/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
@@ -57,11 +57,8 @@
import java.util.Objects;
import java.util.Set;
-/**
- * Maintains a connection to a particular {@link MediaRoute2ProviderService}.
- */
-final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider
- implements ServiceConnection {
+/** Maintains a connection to a particular {@link MediaRoute2ProviderService}. */
+final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider {
private static final String TAG = "MR2ProviderSvcProxy";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
@@ -69,6 +66,7 @@
private final int mUserId;
private final Handler mHandler;
private final boolean mIsSelfScanOnlyProvider;
+ private final ServiceConnection mServiceConnection = new ServiceConnectionImpl();
// Connection state
private boolean mRunning;
@@ -303,9 +301,12 @@
Intent service = new Intent(MediaRoute2ProviderService.SERVICE_INTERFACE);
service.setComponent(mComponentName);
try {
- mBound = mContext.bindServiceAsUser(service, this,
- Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE,
- new UserHandle(mUserId));
+ mBound =
+ mContext.bindServiceAsUser(
+ service,
+ mServiceConnection,
+ Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE,
+ new UserHandle(mUserId));
if (!mBound && DEBUG) {
Slog.d(TAG, this + ": Bind failed");
}
@@ -325,12 +326,11 @@
mBound = false;
disconnect();
- mContext.unbindService(this);
+ mContext.unbindService(mServiceConnection);
}
}
- @Override
- public void onServiceConnected(ComponentName name, IBinder service) {
+ private void onServiceConnectedInternal(IBinder service) {
if (DEBUG) {
Slog.d(TAG, this + ": Connected");
}
@@ -354,16 +354,14 @@
}
}
- @Override
- public void onServiceDisconnected(ComponentName name) {
+ private void onServiceDisconnectedInternal() {
if (DEBUG) {
Slog.d(TAG, this + ": Service disconnected");
}
disconnect();
}
- @Override
- public void onBindingDied(ComponentName name) {
+ private void onBindingDiedInternal(ComponentName name) {
unbind();
if (Flags.enablePreventionOfKeepAliveRouteProviders()) {
Slog.w(
@@ -662,6 +660,37 @@
pendingTransferCount);
}
+ // All methods in this class are called on the main thread.
+ private final class ServiceConnectionImpl implements ServiceConnection {
+
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ if (Flags.enableMr2ServiceNonMainBgThread()) {
+ mHandler.post(() -> onServiceConnectedInternal(service));
+ } else {
+ onServiceConnectedInternal(service);
+ }
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ if (Flags.enableMr2ServiceNonMainBgThread()) {
+ mHandler.post(() -> onServiceDisconnectedInternal());
+ } else {
+ onServiceDisconnectedInternal();
+ }
+ }
+
+ @Override
+ public void onBindingDied(ComponentName name) {
+ if (Flags.enableMr2ServiceNonMainBgThread()) {
+ mHandler.post(() -> onBindingDiedInternal(name));
+ } else {
+ onBindingDiedInternal(name);
+ }
+ }
+ }
+
private final class Connection implements DeathRecipient {
private final IMediaRoute2ProviderService mService;
private final ServiceCallbackStub mCallbackStub;
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
old mode 100755
new mode 100644
diff --git a/services/core/java/com/android/server/pm/DexOptHelper.java b/services/core/java/com/android/server/pm/DexOptHelper.java
index 209cbb7..e34bdc6 100644
--- a/services/core/java/com/android/server/pm/DexOptHelper.java
+++ b/services/core/java/com/android/server/pm/DexOptHelper.java
@@ -728,7 +728,14 @@
final int compilationReason =
dexManager.getCompilationReasonForInstallScenario(
installRequest.getInstallScenario());
- return new DexoptOptions(packageName, compilationReason, dexoptFlags);
+ final AndroidPackage pkg = ps.getPkg();
+ var options = new DexoptOptions(packageName, compilationReason, dexoptFlags);
+ if (installRequest.getDexoptCompilerFilter() != null) {
+ options = options.overrideCompilerFilter(installRequest.getDexoptCompilerFilter());
+ } else if (pkg != null && pkg.isDebuggable()) {
+ options = options.overrideCompilerFilter(DexoptParams.COMPILER_FILTER_NOOP);
+ }
+ return options;
}
/**
@@ -772,12 +779,12 @@
&& installRequest.getInstallSource().mInitiatingPackageName.equals("android"))
: true;
+ // Don't skip the dexopt call if the compiler filter is "skip". Instead, call dexopt with
+ // the "skip" filter so that ART Service gets notified and skips dexopt itself.
return (!instantApp || Global.getInt(context.getContentResolver(),
Global.INSTANT_APP_DEXOPT_ENABLED, 0) != 0)
&& pkg != null
- && !pkg.isDebuggable()
&& (!onIncremental)
- && dexoptOptions.isCompilationEnabled()
&& !isApex
&& performDexOptForRollback;
}
diff --git a/services/core/java/com/android/server/pm/InstallArgs.java b/services/core/java/com/android/server/pm/InstallArgs.java
index 46f9732..8001615 100644
--- a/services/core/java/com/android/server/pm/InstallArgs.java
+++ b/services/core/java/com/android/server/pm/InstallArgs.java
@@ -58,6 +58,8 @@
final int mDataLoaderType;
final int mPackageSource;
final boolean mApplicationEnabledSettingPersistent;
+ @Nullable
+ final String mDexoptCompilerFilter;
// The list of instruction sets supported by this app. This is currently
// only used during the rmdex() phase to clean up resources. We can get rid of this
@@ -73,7 +75,7 @@
int autoRevokePermissionsMode, String traceMethod, int traceCookie,
SigningDetails signingDetails, int installReason, int installScenario,
boolean forceQueryableOverride, int dataLoaderType, int packageSource,
- boolean applicationEnabledSettingPersistent) {
+ boolean applicationEnabledSettingPersistent, String dexoptCompilerFilter) {
mOriginInfo = originInfo;
mMoveInfo = moveInfo;
mInstallFlags = installFlags;
@@ -96,5 +98,6 @@
mDataLoaderType = dataLoaderType;
mPackageSource = packageSource;
mApplicationEnabledSettingPersistent = applicationEnabledSettingPersistent;
+ mDexoptCompilerFilter = dexoptCompilerFilter;
}
}
diff --git a/services/core/java/com/android/server/pm/InstallRequest.java b/services/core/java/com/android/server/pm/InstallRequest.java
index 8f51e36..dd2583a0d 100644
--- a/services/core/java/com/android/server/pm/InstallRequest.java
+++ b/services/core/java/com/android/server/pm/InstallRequest.java
@@ -174,13 +174,13 @@
mUserId = params.getUser().getIdentifier();
mInstallArgs = new InstallArgs(params.mOriginInfo, params.mMoveInfo, params.mObserver,
params.mInstallFlags, params.mDevelopmentInstallFlags, params.mInstallSource,
- params.mVolumeUuid, params.getUser(), null /*instructionSets*/,
+ params.mVolumeUuid, params.getUser(), null /*instructionSets*/,
params.mPackageAbiOverride, params.mPermissionStates,
params.mAllowlistedRestrictedPermissions, params.mAutoRevokePermissionsMode,
params.mTraceMethod, params.mTraceCookie, params.mSigningDetails,
params.mInstallReason, params.mInstallScenario, params.mForceQueryableOverride,
params.mDataLoaderType, params.mPackageSource,
- params.mApplicationEnabledSettingPersistent);
+ params.mApplicationEnabledSettingPersistent, params.mDexoptCompilerFilter);
mPackageLite = params.mPackageLite;
mPackageMetrics = new PackageMetrics(this);
mIsInstallInherit = params.mIsInherit;
@@ -709,6 +709,11 @@
return mWarnings;
}
+ @Nullable
+ public String getDexoptCompilerFilter() {
+ return mInstallArgs != null ? mInstallArgs.mDexoptCompilerFilter : null;
+ }
+
public void setScanFlags(int scanFlags) {
mScanFlags = scanFlags;
}
diff --git a/services/core/java/com/android/server/pm/InstallingSession.java b/services/core/java/com/android/server/pm/InstallingSession.java
index d3a18f9..ccc1175 100644
--- a/services/core/java/com/android/server/pm/InstallingSession.java
+++ b/services/core/java/com/android/server/pm/InstallingSession.java
@@ -102,6 +102,7 @@
@Nullable
final DomainSet mPreVerifiedDomains;
final boolean mHasAppMetadataFile;
+ @Nullable final String mDexoptCompilerFilter;
// For move install
InstallingSession(OriginInfo originInfo, MoveInfo moveInfo, IPackageInstallObserver2 observer,
@@ -136,6 +137,7 @@
mApplicationEnabledSettingPersistent = false;
mPreVerifiedDomains = null;
mHasAppMetadataFile = false;
+ mDexoptCompilerFilter = null;
}
InstallingSession(int sessionId, File stagedDir, IPackageInstallObserver2 observer,
@@ -172,6 +174,7 @@
mApplicationEnabledSettingPersistent = sessionParams.applicationEnabledSettingPersistent;
mPreVerifiedDomains = preVerifiedDomains;
mHasAppMetadataFile = hasAppMetadatafile;
+ mDexoptCompilerFilter = sessionParams.dexoptCompilerFilter;
}
@Override
diff --git a/services/core/java/com/android/server/pm/PackageFreezer.java b/services/core/java/com/android/server/pm/PackageFreezer.java
index 0afda45..11f2059 100644
--- a/services/core/java/com/android/server/pm/PackageFreezer.java
+++ b/services/core/java/com/android/server/pm/PackageFreezer.java
@@ -62,6 +62,12 @@
PackageFreezer(String packageName, int userId, String killReason,
PackageManagerService pm, int exitInfoReason, @Nullable InstallRequest request) {
+ this(packageName, userId, killReason, pm, exitInfoReason, request, false);
+ }
+
+ PackageFreezer(String packageName, int userId, String killReason,
+ PackageManagerService pm, int exitInfoReason, @Nullable InstallRequest request,
+ boolean waitAppKilled) {
mPm = pm;
mPackageName = packageName;
mInstallRequest = request;
@@ -77,7 +83,7 @@
ps = mPm.mSettings.getPackageLPr(mPackageName);
}
if (ps != null) {
- if (Flags.waitApplicationKilled()) {
+ if (waitAppKilled && Flags.waitApplicationKilled()) {
mPm.killApplicationSync(ps.getPackageName(), ps.getAppId(), userId, killReason,
exitInfoReason);
} else {
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 050d44e..b93dcdc 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -1423,7 +1423,9 @@
DevicePolicyManagerInternal dpmi =
LocalServices.getService(DevicePolicyManagerInternal.class);
final boolean canSilentlyInstallPackage =
- dpmi != null && dpmi.canSilentlyInstallPackage(callerPackageName, callingUid);
+ (dpmi != null && dpmi.canSilentlyInstallPackage(callerPackageName, callingUid))
+ || PackageInstallerSession.isEmergencyInstallerEnabled(
+ versionedPackage.getPackageName(), snapshot, userId, callingUid);
final PackageDeleteObserverAdapter adapter = new PackageDeleteObserverAdapter(mContext,
statusReceiver, versionedPackage.getPackageName(),
@@ -1445,15 +1447,6 @@
.createEvent(DevicePolicyEnums.UNINSTALL_PACKAGE)
.setAdmin(callerPackageName)
.write();
- } else if (PackageInstallerSession.isEmergencyInstallerEnabled(callerPackageName, snapshot,
- userId, callingUid)) {
- // Need to clear the calling identity to get DELETE_PACKAGES permission
- final long ident = Binder.clearCallingIdentity();
- try {
- mPm.deletePackageVersioned(versionedPackage, adapter.getBinder(), userId, flags);
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
} else {
ApplicationInfo appInfo = snapshot.getApplicationInfo(callerPackageName, 0, userId);
if (appInfo.targetSdkVersion >= Build.VERSION_CODES.P) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index ca84d68..66a93d7 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -4347,7 +4347,14 @@
public PackageFreezer freezePackage(String packageName, int userId, String killReason,
int exitInfoReason, InstallRequest request) {
- return new PackageFreezer(packageName, userId, killReason, this, exitInfoReason, request);
+ return freezePackage(packageName, userId, killReason, exitInfoReason, request,
+ /* waitAppKilled= */ false);
+ }
+
+ private PackageFreezer freezePackage(String packageName, int userId, String killReason,
+ int exitInfoReason, InstallRequest request, boolean waitAppKilled) {
+ return new PackageFreezer(packageName, userId, killReason, this, exitInfoReason, request,
+ waitAppKilled);
}
public PackageFreezer freezePackageForDelete(String packageName, int userId, int deleteFlags,
@@ -4772,7 +4779,8 @@
final boolean succeeded;
try (PackageFreezer freezer = freezePackage(packageName, UserHandle.USER_ALL,
"clearApplicationUserData",
- ApplicationExitInfo.REASON_USER_REQUESTED, null /* request */)) {
+ ApplicationExitInfo.REASON_USER_REQUESTED, null /* request */,
+ /* waitAppKilled= */ true)) {
try (PackageManagerTracedLock installLock = mInstallLock.acquireLock()) {
succeeded = clearApplicationUserDataLIF(snapshotComputer(), packageName,
userId);
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java b/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java
index e2ddba5..819a75c 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java
@@ -18,7 +18,7 @@
import android.os.SystemProperties;
-import com.android.server.pm.dex.DexoptOptions;
+import com.android.server.art.model.DexoptParams;
import dalvik.system.DexFile;
@@ -71,7 +71,7 @@
private static String getAndCheckValidity(int reason) {
String sysPropValue = SystemProperties.get(getSystemPropertyName(reason));
if (sysPropValue == null || sysPropValue.isEmpty()
- || !(sysPropValue.equals(DexoptOptions.COMPILER_FILTER_NOOP)
+ || !(sysPropValue.equals(DexoptParams.COMPILER_FILTER_NOOP)
|| DexFile.isValidCompilerFilter(sysPropValue))) {
throw new IllegalStateException("Value \"" + sysPropValue +"\" not valid "
+ "(reason " + REASON_STRINGS[reason] + ")");
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index a876616..7a53fe7 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -121,6 +121,8 @@
import com.android.server.LocalServices;
import com.android.server.SystemConfig;
import com.android.server.art.ArtManagerLocal;
+import com.android.server.art.ReasonMapping;
+import com.android.server.art.model.DexoptParams;
import com.android.server.pm.PackageManagerShellCommandDataLoader.Metadata;
import com.android.server.pm.permission.LegacyPermissionManagerInternal;
import com.android.server.pm.permission.PermissionAllowlist;
@@ -3589,6 +3591,14 @@
case "--package-source":
sessionParams.setPackageSource(Integer.parseInt(getNextArg()));
break;
+ case "--dexopt-compiler-filter":
+ sessionParams.dexoptCompilerFilter = getNextArgRequired();
+ // An early check that throws IllegalArgumentException if the compiler filter is
+ // invalid.
+ new DexoptParams.Builder(ReasonMapping.REASON_INSTALL)
+ .setCompilerFilter(sessionParams.dexoptCompilerFilter)
+ .build();
+ break;
default:
throw new IllegalArgumentException("Unknown option " + opt);
}
@@ -4735,6 +4745,7 @@
pw.println(" [--force-uuid internal|UUID] [--pkg PACKAGE] [-S BYTES]");
pw.println(" [--apex] [--non-staged] [--force-non-staged]");
pw.println(" [--staged-ready-timeout TIMEOUT] [--ignore-dexopt-profile]");
+ pw.println(" [--dexopt-compiler-filter FILTER]");
pw.println(" [PATH [SPLIT...]|-]");
pw.println(" Install an application. Must provide the apk data to install, either as");
pw.println(" file path(s) or '-' to read from stdin. Options are:");
@@ -4781,13 +4792,19 @@
pw.println(" milliseconds for pre-reboot verification to complete when");
pw.println(" performing staged install. This flag is used to alter the waiting");
pw.println(" time. You can skip the waiting time by specifying a TIMEOUT of '0'");
- pw.println(" --ignore-dexopt-profile: If set, all profiles are ignored by dexopt");
+ pw.println(" --ignore-dexopt-profile: if set, all profiles are ignored by dexopt");
pw.println(" during the installation, including the profile in the DM file and");
pw.println(" the profile embedded in the APK file. If an invalid profile is");
pw.println(" provided during installation, no warning will be reported by `adb");
pw.println(" install`.");
pw.println(" This option does not affect later dexopt operations (e.g.,");
pw.println(" background dexopt and manual `pm compile` invocations).");
+ pw.println(" --dexopt-compiler-filter: the target compiler filter for dexopt during");
+ pw.println(" the installation. The filter actually used may be different.");
+ pw.println(" Valid values: one of the values documented in");
+ pw.println(" https://source.android.com/docs/core/runtime/configure"
+ + "#compiler_filters");
+ pw.println(" or 'skip'");
pw.println("");
pw.println(" install-existing [--user USER_ID|all|current]");
pw.println(" [--instant] [--full] [--wait] [--restrict-permissions] PACKAGE");
diff --git a/services/core/java/com/android/server/pm/PackageMetrics.java b/services/core/java/com/android/server/pm/PackageMetrics.java
index 2081f73..0acadb1 100644
--- a/services/core/java/com/android/server/pm/PackageMetrics.java
+++ b/services/core/java/com/android/server/pm/PackageMetrics.java
@@ -16,7 +16,12 @@
package com.android.server.pm;
+import static android.content.pm.PackageManager.GET_RESOLVED_FILTER;
+import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
+import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
+import static android.content.pm.PackageManager.MATCH_DISABLED_COMPONENTS;
import static android.os.Process.INVALID_UID;
+import static android.os.Process.SYSTEM_UID;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -25,6 +30,7 @@
import android.app.ActivityManager;
import android.app.admin.SecurityLog;
import android.content.ComponentName;
+import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.Flags;
import android.content.pm.PackageManager;
@@ -376,7 +382,30 @@
mCallingUid = callingUid;
}
- public boolean isSameComponent(ActivityInfo activityInfo) {
+ public boolean isLauncherActivity(@NonNull Computer computer, @UserIdInt int userId) {
+ if (mIsForWholeApp) {
+ return false;
+ }
+ // Query the launcher activities with the package name.
+ final Intent intent = new Intent(Intent.ACTION_MAIN);
+ intent.addCategory(Intent.CATEGORY_LAUNCHER);
+ intent.setPackage(mPackageName);
+ List<ResolveInfo> launcherActivities = computer.queryIntentActivitiesInternal(
+ intent, null,
+ MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE | GET_RESOLVED_FILTER
+ | MATCH_DISABLED_COMPONENTS, SYSTEM_UID, userId);
+ final int launcherActivitiesSize =
+ launcherActivities != null ? launcherActivities.size() : 0;
+ for (int i = 0; i < launcherActivitiesSize; i++) {
+ ResolveInfo resolveInfo = launcherActivities.get(i);
+ if (isSameComponent(resolveInfo.activityInfo)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean isSameComponent(ActivityInfo activityInfo) {
if (activityInfo == null) {
return false;
}
@@ -395,25 +424,13 @@
Slog.d(TAG, "Fail to report component state due to metrics is empty");
return;
}
- boolean isLauncher = false;
- final List<ResolveInfo> resolveInfosForLauncher = getHomeActivitiesResolveInfoAsUser(
- computer, userId);
- final int resolveInfosForLauncherSize =
- resolveInfosForLauncher != null ? resolveInfosForLauncher.size() : 0;
final int metricsSize = componentStateMetricsList.size();
for (int i = 0; i < metricsSize; i++) {
final ComponentStateMetrics componentStateMetrics = componentStateMetricsList.get(i);
- for (int j = 0; j < resolveInfosForLauncherSize; j++) {
- ResolveInfo resolveInfo = resolveInfosForLauncher.get(j);
- if (componentStateMetrics.isSameComponent(resolveInfo.activityInfo)) {
- isLauncher = true;
- break;
- }
- }
reportComponentStateChanged(componentStateMetrics.mUid,
componentStateMetrics.mComponentOldState,
componentStateMetrics.mComponentNewState,
- isLauncher,
+ componentStateMetrics.isLauncherActivity(computer, userId),
componentStateMetrics.mIsForWholeApp,
componentStateMetrics.mCallingUid);
}
@@ -424,10 +441,4 @@
FrameworkStatsLog.write(FrameworkStatsLog.COMPONENT_STATE_CHANGED_REPORTED,
uid, componentOldState, componentNewState, isLauncher, isForWholeApp, callingUid);
}
-
- private static List<ResolveInfo> getHomeActivitiesResolveInfoAsUser(@NonNull Computer computer,
- @UserIdInt int userId) {
- return computer.queryIntentActivitiesInternal(computer.getHomeIntent(), /* resolvedType */
- null, /* flags */ 0, userId);
- }
}
diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
index 483d308..95e5b84 100644
--- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
+++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
@@ -156,7 +156,8 @@
UserManager.DISALLOW_NEAR_FIELD_COMMUNICATION_RADIO,
UserManager.DISALLOW_SIM_GLOBALLY,
UserManager.DISALLOW_ASSIST_CONTENT,
- UserManager.DISALLOW_THREAD_NETWORK
+ UserManager.DISALLOW_THREAD_NETWORK,
+ UserManager.DISALLOW_CHANGE_NEAR_FIELD_COMMUNICATION_RADIO
});
public static final Set<String> DEPRECATED_USER_RESTRICTIONS = Sets.newArraySet(
@@ -208,7 +209,8 @@
UserManager.DISALLOW_CELLULAR_2G,
UserManager.DISALLOW_ULTRA_WIDEBAND_RADIO,
UserManager.DISALLOW_NEAR_FIELD_COMMUNICATION_RADIO,
- UserManager.DISALLOW_THREAD_NETWORK
+ UserManager.DISALLOW_THREAD_NETWORK,
+ UserManager.DISALLOW_CHANGE_NEAR_FIELD_COMMUNICATION_RADIO
);
/**
@@ -254,7 +256,8 @@
UserManager.DISALLOW_CELLULAR_2G,
UserManager.DISALLOW_ULTRA_WIDEBAND_RADIO,
UserManager.DISALLOW_NEAR_FIELD_COMMUNICATION_RADIO,
- UserManager.DISALLOW_THREAD_NETWORK
+ UserManager.DISALLOW_THREAD_NETWORK,
+ UserManager.DISALLOW_CHANGE_NEAR_FIELD_COMMUNICATION_RADIO
);
/**
diff --git a/services/core/java/com/android/server/pm/dex/DexoptOptions.java b/services/core/java/com/android/server/pm/dex/DexoptOptions.java
index fcdc008..8cf248d 100644
--- a/services/core/java/com/android/server/pm/dex/DexoptOptions.java
+++ b/services/core/java/com/android/server/pm/dex/DexoptOptions.java
@@ -73,12 +73,6 @@
// or device setup and should be scheduled appropriately.
public static final int DEXOPT_FOR_RESTORE = 1 << 11; // TODO(b/135202722): remove
- /**
- * A value indicating that dexopt shouldn't be run. This string is only used when loading
- * filters from the `pm.dexopt.install*` properties and is not propagated to dex2oat.
- */
- public static final String COMPILER_FILTER_NOOP = "skip";
-
// The name of package to optimize.
private final String mPackageName;
@@ -186,10 +180,6 @@
return mCompilationReason;
}
- public boolean isCompilationEnabled() {
- return !mCompilerFilter.equals(COMPILER_FILTER_NOOP);
- }
-
/**
* Creates a new set of DexoptOptions which are the same with the exception of the compiler
* filter (set to the given value).
diff --git a/services/core/java/com/android/server/pm/permission/AccessCheckDelegate.java b/services/core/java/com/android/server/pm/permission/AccessCheckDelegate.java
index 3edd697..f518769 100644
--- a/services/core/java/com/android/server/pm/permission/AccessCheckDelegate.java
+++ b/services/core/java/com/android/server/pm/permission/AccessCheckDelegate.java
@@ -38,6 +38,7 @@
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.function.DodecFunction;
+import com.android.internal.util.function.HexConsumer;
import com.android.internal.util.function.HexFunction;
import com.android.internal.util.function.OctFunction;
import com.android.internal.util.function.QuadFunction;
@@ -269,8 +270,8 @@
if (isDelegatePermission(permissionName)) {
final long identity = Binder.clearCallingIdentity();
try {
- return checkPermission(SHELL_PKG, permissionName,
- persistentDeviceId, userId, superImpl);
+ return checkPermission(SHELL_PKG, permissionName, persistentDeviceId,
+ userId, superImpl);
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -323,8 +324,7 @@
Process.SHELL_UID);
final long identity = Binder.clearCallingIdentity();
try {
- return superImpl.apply(code, shellUid, "com.android.shell", null,
- virtualDeviceId, raw);
+ return superImpl.apply(code, shellUid, SHELL_PKG, null, virtualDeviceId, raw);
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -340,7 +340,7 @@
Process.SHELL_UID);
final long identity = Binder.clearCallingIdentity();
try {
- return superImpl.apply(code, usage, shellUid, "com.android.shell");
+ return superImpl.apply(code, usage, shellUid, SHELL_PKG);
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -359,9 +359,8 @@
Process.SHELL_UID);
final long identity = Binder.clearCallingIdentity();
try {
- return superImpl.apply(code, shellUid, "com.android.shell", featureId,
- virtualDeviceId, shouldCollectAsyncNotedOp, message,
- shouldCollectMessage);
+ return superImpl.apply(code, shellUid, SHELL_PKG, featureId, virtualDeviceId,
+ shouldCollectAsyncNotedOp, message, shouldCollectMessage);
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -382,8 +381,8 @@
final long identity = Binder.clearCallingIdentity();
try {
return superImpl.apply(code,
- new AttributionSource(shellUid, Process.INVALID_PID,
- "com.android.shell", attributionSource.getAttributionTag(),
+ new AttributionSource(shellUid, Process.INVALID_PID, SHELL_PKG,
+ attributionSource.getAttributionTag(),
attributionSource.getToken(), /*renouncedPermissions*/ null,
attributionSource.getDeviceId(), attributionSource.getNext()),
shouldCollectAsyncNotedOp, message, shouldCollectMessage,
@@ -409,10 +408,9 @@
Process.SHELL_UID);
final long identity = Binder.clearCallingIdentity();
try {
- return superImpl.apply(token, code, shellUid, "com.android.shell",
- attributionTag, virtualDeviceId, startIfModeDefault,
- shouldCollectAsyncNotedOp, message, shouldCollectMessage,
- attributionFlags, attributionChainId);
+ return superImpl.apply(token, code, shellUid, SHELL_PKG, attributionTag,
+ virtualDeviceId, startIfModeDefault, shouldCollectAsyncNotedOp, message,
+ shouldCollectMessage, attributionFlags, attributionChainId);
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -438,8 +436,8 @@
final long identity = Binder.clearCallingIdentity();
try {
return superImpl.apply(clientId, code,
- new AttributionSource(shellUid, Process.INVALID_PID,
- "com.android.shell", attributionSource.getAttributionTag(),
+ new AttributionSource(shellUid, Process.INVALID_PID, SHELL_PKG,
+ attributionSource.getAttributionTag(),
attributionSource.getToken(), /*renouncedPermissions*/ null,
attributionSource.getDeviceId(), attributionSource.getNext()),
startIfModeDefault, shouldCollectAsyncNotedOp, message,
@@ -465,11 +463,12 @@
final long identity = Binder.clearCallingIdentity();
try {
superImpl.apply(clientId, code,
- new AttributionSource(shellUid, Process.INVALID_PID,
- "com.android.shell", attributionSource.getAttributionTag(),
+ new AttributionSource(shellUid, Process.INVALID_PID, SHELL_PKG,
+ attributionSource.getAttributionTag(),
attributionSource.getToken(), /*renouncedPermissions*/ null,
attributionSource.getDeviceId(), attributionSource.getNext()),
skipProxyOperation);
+ return;
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -477,6 +476,26 @@
superImpl.apply(clientId, code, attributionSource, skipProxyOperation);
}
+ @Override
+ public void finishOperation(IBinder clientId, int code, int uid, String packageName,
+ String attributionTag, int virtualDeviceId, @NonNull HexConsumer<IBinder, Integer,
+ Integer, String, String, Integer> superImpl) {
+ if (uid == mDelegateAndOwnerUid && isDelegateOp(code)) {
+ final int shellUid =
+ UserHandle.getUid(UserHandle.getUserId(uid), Process.SHELL_UID);
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ superImpl.accept(clientId, code, shellUid, SHELL_PKG, attributionTag,
+ virtualDeviceId);
+ return;
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+ superImpl.accept(clientId, code, uid, packageName, attributionTag,
+ virtualDeviceId);
+ }
+
private boolean isDelegatePermission(@NonNull String permission) {
// null permissions means all permissions are delegated
return mDelegateAndOwnerUid != INVALID_UID
diff --git a/services/core/java/com/android/server/pm/permission/LegacyPermissionManagerService.java b/services/core/java/com/android/server/pm/permission/LegacyPermissionManagerService.java
index 23872d4f..119b659 100644
--- a/services/core/java/com/android/server/pm/permission/LegacyPermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/LegacyPermissionManagerService.java
@@ -336,8 +336,13 @@
final PermissionManagerServiceInternal permissionManagerInternal =
LocalServices.getService(PermissionManagerServiceInternal.class);
for (final int userId : UserManagerService.getInstance().getUserIds()) {
- packageManagerInternal.forEachPackage(pkg ->
- permissionManagerInternal.resetRuntimePermissions(pkg, userId));
+ packageManagerInternal.forEachPackage(pkg -> {
+ // Filter out packages that don't have app IDs which means they don't have
+ // permission states either.
+ if (pkg.getUid() != -1) {
+ permissionManagerInternal.resetRuntimePermissions(pkg, userId);
+ }
+ });
}
}
diff --git a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
index 5bae5a4..322ed86 100644
--- a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
+++ b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
@@ -298,6 +298,8 @@
private final MobileRadioPowerStatsCollector mMobileRadioPowerStatsCollector;
private final WifiPowerStatsCollector mWifiPowerStatsCollector;
private final BluetoothPowerStatsCollector mBluetoothPowerStatsCollector;
+ private final CameraPowerStatsCollector mCameraPowerStatsCollector;
+ private final GnssPowerStatsCollector mGnssPowerStatsCollector;
private final SparseBooleanArray mPowerStatsCollectorEnabled = new SparseBooleanArray();
private final WifiPowerStatsCollector.WifiStatsRetriever mWifiStatsRetriever =
new WifiPowerStatsCollector.WifiStatsRetriever() {
@@ -1963,7 +1965,7 @@
private class PowerStatsCollectorInjector implements CpuPowerStatsCollector.Injector,
MobileRadioPowerStatsCollector.Injector, WifiPowerStatsCollector.Injector,
- BluetoothPowerStatsCollector.Injector {
+ BluetoothPowerStatsCollector.Injector, EnergyConsumerPowerStatsCollector.Injector {
private PackageManager mPackageManager;
private PowerStatsCollector.ConsumedEnergyRetriever mConsumedEnergyRetriever;
private NetworkStatsManager mNetworkStatsManager;
@@ -5446,7 +5448,10 @@
final int mappedUid = mapUid(uid);
if (mGpsNesting == 0) {
mHistory.recordStateStartEvent(elapsedRealtimeMs, uptimeMs,
- HistoryItem.STATE_GPS_ON_FLAG);
+ HistoryItem.STATE_GPS_ON_FLAG, uid, "gnss");
+ if (mPowerStatsCollectorEnabled.get(BatteryConsumer.POWER_COMPONENT_GNSS)) {
+ mGnssPowerStatsCollector.schedule();
+ }
}
mGpsNesting++;
@@ -5465,11 +5470,14 @@
mGpsNesting--;
if (mGpsNesting == 0) {
mHistory.recordStateStopEvent(elapsedRealtimeMs, uptimeMs,
- HistoryItem.STATE_GPS_ON_FLAG);
+ HistoryItem.STATE_GPS_ON_FLAG, uid, "gnss");
mHistory.recordGpsSignalQualityEvent(elapsedRealtimeMs, uptimeMs,
GPS_SIGNAL_QUALITY_NONE);
stopAllGpsSignalQualityTimersLocked(-1, elapsedRealtimeMs);
mGpsSignalQualityBin = -1;
+ if (mPowerStatsCollectorEnabled.get(BatteryConsumer.POWER_COMPONENT_GNSS)) {
+ mGnssPowerStatsCollector.schedule();
+ }
}
mFrameworkStatsLogger.gpsScanStateChanged(mapIsolatedUid(uid), workChain, /* on */ false);
@@ -6652,13 +6660,17 @@
uid = mapUid(uid);
if (mCameraOnNesting++ == 0) {
mHistory.recordState2StartEvent(elapsedRealtimeMs, uptimeMs,
- HistoryItem.STATE2_CAMERA_FLAG);
+ HistoryItem.STATE2_CAMERA_FLAG, uid, "camera");
mCameraOnTimer.startRunningLocked(elapsedRealtimeMs);
}
getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs)
.noteCameraTurnedOnLocked(elapsedRealtimeMs);
- scheduleSyncExternalStatsLocked("camera-on", ExternalStatsSync.UPDATE_CAMERA);
+ if (mPowerStatsCollectorEnabled.get(BatteryConsumer.POWER_COMPONENT_CAMERA)) {
+ mCameraPowerStatsCollector.schedule();
+ } else {
+ scheduleSyncExternalStatsLocked("camera-on", ExternalStatsSync.UPDATE_CAMERA);
+ }
}
@GuardedBy("this")
@@ -6669,13 +6681,17 @@
uid = mapUid(uid);
if (--mCameraOnNesting == 0) {
mHistory.recordState2StopEvent(elapsedRealtimeMs, uptimeMs,
- HistoryItem.STATE2_CAMERA_FLAG);
+ HistoryItem.STATE2_CAMERA_FLAG, uid, "camera");
mCameraOnTimer.stopRunningLocked(elapsedRealtimeMs);
}
getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs)
.noteCameraTurnedOffLocked(elapsedRealtimeMs);
- scheduleSyncExternalStatsLocked("camera-off", ExternalStatsSync.UPDATE_CAMERA);
+ if (mPowerStatsCollectorEnabled.get(BatteryConsumer.POWER_COMPONENT_CAMERA)) {
+ mCameraPowerStatsCollector.schedule();
+ } else {
+ scheduleSyncExternalStatsLocked("camera-off", ExternalStatsSync.UPDATE_CAMERA);
+ }
}
@GuardedBy("this")
@@ -11281,6 +11297,12 @@
mPowerStatsCollectorInjector);
mBluetoothPowerStatsCollector.addConsumer(this::recordPowerStats);
+ mCameraPowerStatsCollector = new CameraPowerStatsCollector(mPowerStatsCollectorInjector);
+ mCameraPowerStatsCollector.addConsumer(this::recordPowerStats);
+
+ mGnssPowerStatsCollector = new GnssPowerStatsCollector(mPowerStatsCollectorInjector);
+ mGnssPowerStatsCollector.addConsumer(this::recordPowerStats);
+
mStartCount++;
initTimersAndCounters();
mOnBattery = mOnBatteryInternal = false;
@@ -14703,6 +14725,14 @@
mPowerStatsCollectorEnabled.get(BatteryConsumer.POWER_COMPONENT_BLUETOOTH));
mBluetoothPowerStatsCollector.schedule();
+ mCameraPowerStatsCollector.setEnabled(
+ mPowerStatsCollectorEnabled.get(BatteryConsumer.POWER_COMPONENT_CAMERA));
+ mCameraPowerStatsCollector.schedule();
+
+ mGnssPowerStatsCollector.setEnabled(
+ mPowerStatsCollectorEnabled.get(BatteryConsumer.POWER_COMPONENT_GNSS));
+ mGnssPowerStatsCollector.schedule();
+
mSystemReady = true;
}
@@ -14721,6 +14751,10 @@
return mWifiPowerStatsCollector;
case BatteryConsumer.POWER_COMPONENT_BLUETOOTH:
return mBluetoothPowerStatsCollector;
+ case BatteryConsumer.POWER_COMPONENT_CAMERA:
+ return mCameraPowerStatsCollector;
+ case BatteryConsumer.POWER_COMPONENT_GNSS:
+ return mGnssPowerStatsCollector;
}
return null;
}
@@ -16258,6 +16292,8 @@
mMobileRadioPowerStatsCollector.forceSchedule();
mWifiPowerStatsCollector.forceSchedule();
mBluetoothPowerStatsCollector.forceSchedule();
+ mCameraPowerStatsCollector.forceSchedule();
+ mGnssPowerStatsCollector.forceSchedule();
}
/**
@@ -16278,6 +16314,8 @@
mMobileRadioPowerStatsCollector.collectAndDump(pw);
mWifiPowerStatsCollector.collectAndDump(pw);
mBluetoothPowerStatsCollector.collectAndDump(pw);
+ mCameraPowerStatsCollector.collectAndDump(pw);
+ mGnssPowerStatsCollector.collectAndDump(pw);
}
private final Runnable mWriteAsyncRunnable = () -> {
diff --git a/services/core/java/com/android/server/power/stats/BatteryUsageStatsProvider.java b/services/core/java/com/android/server/power/stats/BatteryUsageStatsProvider.java
index ba6e4a9..ce0ee39 100644
--- a/services/core/java/com/android/server/power/stats/BatteryUsageStatsProvider.java
+++ b/services/core/java/com/android/server/power/stats/BatteryUsageStatsProvider.java
@@ -95,8 +95,12 @@
}
mPowerCalculators.add(new SensorPowerCalculator(
mContext.getSystemService(SensorManager.class)));
- mPowerCalculators.add(new GnssPowerCalculator(mPowerProfile));
- mPowerCalculators.add(new CameraPowerCalculator(mPowerProfile));
+ if (!mPowerStatsExporterEnabled.get(BatteryConsumer.POWER_COMPONENT_GNSS)) {
+ mPowerCalculators.add(new GnssPowerCalculator(mPowerProfile));
+ }
+ if (!mPowerStatsExporterEnabled.get(BatteryConsumer.POWER_COMPONENT_CAMERA)) {
+ mPowerCalculators.add(new CameraPowerCalculator(mPowerProfile));
+ }
if (!mPowerStatsExporterEnabled.get(BatteryConsumer.POWER_COMPONENT_FLASHLIGHT)) {
mPowerCalculators.add(new FlashlightPowerCalculator(mPowerProfile));
}
diff --git a/services/core/java/com/android/server/power/stats/BinaryStatePowerStatsProcessor.java b/services/core/java/com/android/server/power/stats/BinaryStatePowerStatsProcessor.java
index 490bd5e..599e63d 100644
--- a/services/core/java/com/android/server/power/stats/BinaryStatePowerStatsProcessor.java
+++ b/services/core/java/com/android/server/power/stats/BinaryStatePowerStatsProcessor.java
@@ -51,7 +51,7 @@
private long mLastUpdateTimestamp;
private PowerStats.Descriptor mDescriptor;
- private final BinaryStatePowerStatsLayout mStatsLayout = new BinaryStatePowerStatsLayout();
+ private final BinaryStatePowerStatsLayout mStatsLayout;
private PowerStats mPowerStats;
private PowerEstimationPlan mPlan;
private long[] mTmpDeviceStatsArray;
@@ -59,9 +59,17 @@
BinaryStatePowerStatsProcessor(int powerComponentId,
PowerStatsUidResolver uidResolver, double averagePowerMilliAmp) {
+ this(powerComponentId, uidResolver, averagePowerMilliAmp,
+ new BinaryStatePowerStatsLayout());
+ }
+
+ BinaryStatePowerStatsProcessor(int powerComponentId,
+ PowerStatsUidResolver uidResolver, double averagePowerMilliAmp,
+ BinaryStatePowerStatsLayout statsLayout) {
mPowerComponentId = powerComponentId;
mUsageBasedPowerEstimator = new UsageBasedPowerEstimator(averagePowerMilliAmp);
mUidResolver = uidResolver;
+ mStatsLayout = statsLayout;
}
protected abstract @BinaryState int getBinaryState(BatteryStats.HistoryItem item);
@@ -107,7 +115,7 @@
mInitiatingUid = mUidResolver.mapUid(item.eventTag.uid);
}
} else {
- recordUsageDuration(item.time);
+ recordUsageDuration(mPowerStats, mInitiatingUid, item.time);
mInitiatingUid = Process.INVALID_UID;
if (!mEnergyConsumerSupported) {
flushPowerStats(stats, item.time);
@@ -117,20 +125,16 @@
mLastState = state;
}
- private void recordUsageDuration(long time) {
- if (mLastState == STATE_OFF) {
- return;
- }
-
+ protected void recordUsageDuration(PowerStats powerStats, int uid, long time) {
long durationMs = time - mLastStateTimestamp;
mStatsLayout.setUsageDuration(mPowerStats.stats,
mStatsLayout.getUsageDuration(mPowerStats.stats) + durationMs);
- if (mInitiatingUid != Process.INVALID_UID) {
- long[] uidStats = mPowerStats.uidStats.get(mInitiatingUid);
+ if (uid != Process.INVALID_UID) {
+ long[] uidStats = mPowerStats.uidStats.get(uid);
if (uidStats == null) {
uidStats = new long[mDescriptor.uidStatsArrayLength];
- mPowerStats.uidStats.put(mInitiatingUid, uidStats);
+ mPowerStats.uidStats.put(uid, uidStats);
mStatsLayout.setUidUsageDuration(uidStats, durationMs);
} else {
mStatsLayout.setUsageDuration(mPowerStats.stats,
@@ -143,7 +147,11 @@
void addPowerStats(PowerComponentAggregatedPowerStats stats, PowerStats powerStats,
long timestampMs) {
ensureInitialized();
- recordUsageDuration(timestampMs);
+
+ if (mLastState == STATE_ON) {
+ recordUsageDuration(mPowerStats, mInitiatingUid, timestampMs);
+ }
+
long consumedEnergy = mStatsLayout.getConsumedEnergy(powerStats.stats, 0);
if (consumedEnergy != BatteryStats.POWER_DATA_UNAVAILABLE) {
mEnergyConsumerSupported = true;
@@ -169,14 +177,16 @@
@Override
void finish(PowerComponentAggregatedPowerStats stats, long timestampMs) {
- recordUsageDuration(timestampMs);
+ if (mLastState == STATE_ON) {
+ recordUsageDuration(mPowerStats, mInitiatingUid, timestampMs);
+ }
flushPowerStats(stats, timestampMs);
if (mPlan == null) {
mPlan = new PowerEstimationPlan(stats.getConfig());
}
- computeDevicePowerEstimates(stats);
+ computeDevicePowerEstimates(stats, mPlan, mEnergyConsumerSupported);
combineDevicePowerEstimates(stats);
List<Integer> uids = new ArrayList<>();
@@ -186,9 +196,10 @@
computeUidPowerEstimates(stats, uids);
}
- private void computeDevicePowerEstimates(PowerComponentAggregatedPowerStats stats) {
- for (int i = mPlan.deviceStateEstimations.size() - 1; i >= 0; i--) {
- DeviceStateEstimation estimation = mPlan.deviceStateEstimations.get(i);
+ protected void computeDevicePowerEstimates(PowerComponentAggregatedPowerStats stats,
+ PowerEstimationPlan plan, boolean energyConsumerSupported) {
+ for (int i = plan.deviceStateEstimations.size() - 1; i >= 0; i--) {
+ DeviceStateEstimation estimation = plan.deviceStateEstimations.get(i);
if (!stats.getDeviceStats(mTmpDeviceStatsArray, estimation.stateValues)) {
continue;
}
@@ -196,7 +207,7 @@
long duration = mStatsLayout.getUsageDuration(mTmpDeviceStatsArray);
if (duration > 0) {
double power;
- if (mEnergyConsumerSupported) {
+ if (energyConsumerSupported) {
power = uCtoMah(mStatsLayout.getConsumedEnergy(mTmpDeviceStatsArray, 0));
} else {
power = mUsageBasedPowerEstimator.calculatePower(duration);
diff --git a/services/core/java/com/android/server/power/stats/CameraPowerStatsCollector.java b/services/core/java/com/android/server/power/stats/CameraPowerStatsCollector.java
new file mode 100644
index 0000000..8705bd5
--- /dev/null
+++ b/services/core/java/com/android/server/power/stats/CameraPowerStatsCollector.java
@@ -0,0 +1,30 @@
+/*
+ * 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.power.stats;
+
+import android.hardware.power.stats.EnergyConsumerType;
+import android.os.BatteryConsumer;
+
+public class CameraPowerStatsCollector extends EnergyConsumerPowerStatsCollector {
+
+ CameraPowerStatsCollector(Injector injector) {
+ super(injector, BatteryConsumer.POWER_COMPONENT_CAMERA,
+ BatteryConsumer.powerComponentIdToString(BatteryConsumer.POWER_COMPONENT_CAMERA),
+ EnergyConsumerType.CAMERA, /* energy consumer name */ null,
+ new BinaryStatePowerStatsLayout());
+ }
+}
diff --git a/services/core/java/com/android/server/power/stats/CameraPowerStatsProcessor.java b/services/core/java/com/android/server/power/stats/CameraPowerStatsProcessor.java
new file mode 100644
index 0000000..15c3eb8
--- /dev/null
+++ b/services/core/java/com/android/server/power/stats/CameraPowerStatsProcessor.java
@@ -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.server.power.stats;
+
+import android.os.BatteryConsumer;
+import android.os.BatteryStats;
+
+import com.android.internal.os.PowerProfile;
+
+public class CameraPowerStatsProcessor extends BinaryStatePowerStatsProcessor {
+ public CameraPowerStatsProcessor(PowerProfile powerProfile,
+ PowerStatsUidResolver uidResolver) {
+ super(BatteryConsumer.POWER_COMPONENT_CAMERA, uidResolver,
+ powerProfile.getAveragePower(PowerProfile.POWER_CAMERA));
+ }
+
+ @Override
+ protected @BinaryState int getBinaryState(BatteryStats.HistoryItem item) {
+ return (item.states2 & BatteryStats.HistoryItem.STATE2_CAMERA_FLAG) != 0
+ ? STATE_ON
+ : STATE_OFF;
+ }
+}
diff --git a/services/core/java/com/android/server/power/stats/EnergyConsumerPowerStatsCollector.java b/services/core/java/com/android/server/power/stats/EnergyConsumerPowerStatsCollector.java
new file mode 100644
index 0000000..2021f85
--- /dev/null
+++ b/services/core/java/com/android/server/power/stats/EnergyConsumerPowerStatsCollector.java
@@ -0,0 +1,150 @@
+/*
+ * 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.power.stats;
+
+import android.hardware.power.stats.EnergyConsumerType;
+import android.os.Handler;
+import android.os.PersistableBundle;
+import android.util.Slog;
+
+import com.android.internal.os.Clock;
+import com.android.internal.os.PowerStats;
+
+import java.util.function.IntSupplier;
+
+public class EnergyConsumerPowerStatsCollector extends PowerStatsCollector {
+ private static final String TAG = "CameraPowerStatsCollector";
+
+ private static final long CAMERA_ACTIVITY_REQUEST_TIMEOUT = 20000;
+
+ private static final long ENERGY_UNSPECIFIED = -1;
+
+ interface Injector {
+ Handler getHandler();
+ Clock getClock();
+ PowerStatsUidResolver getUidResolver();
+ long getPowerStatsCollectionThrottlePeriod(String powerComponentName);
+ ConsumedEnergyRetriever getConsumedEnergyRetriever();
+ IntSupplier getVoltageSupplier();
+ }
+
+ private final Injector mInjector;
+ private final int mPowerComponentId;
+ private final String mPowerComponentName;
+ private final int mEnergyConsumerType;
+ private final String mEnergyConsumerName;
+
+ private final BinaryStatePowerStatsLayout mLayout;
+ private boolean mIsInitialized;
+
+ private PowerStats mPowerStats;
+ private ConsumedEnergyRetriever mConsumedEnergyRetriever;
+ private IntSupplier mVoltageSupplier;
+ private int[] mEnergyConsumerIds = new int[0];
+ private long mLastConsumedEnergyUws = ENERGY_UNSPECIFIED;
+ private int mLastVoltageMv;
+ private long mLastUpdateTimestamp;
+ private boolean mFirstCollection = true;
+
+ EnergyConsumerPowerStatsCollector(Injector injector, int powerComponentId,
+ String powerComponentName, @EnergyConsumerType int energyConsumerType,
+ String energyConsumerName, BinaryStatePowerStatsLayout statsLayout) {
+ super(injector.getHandler(),
+ injector.getPowerStatsCollectionThrottlePeriod(powerComponentName),
+ injector.getUidResolver(), injector.getClock());
+ mInjector = injector;
+ mPowerComponentId = powerComponentId;
+ mPowerComponentName = powerComponentName;
+ mEnergyConsumerType = energyConsumerType;
+ mEnergyConsumerName = energyConsumerName;
+ mLayout = statsLayout;
+ }
+
+ private boolean ensureInitialized() {
+ if (mIsInitialized) {
+ return true;
+ }
+
+ if (!isEnabled()) {
+ return false;
+ }
+
+ mConsumedEnergyRetriever = mInjector.getConsumedEnergyRetriever();
+ mVoltageSupplier = mInjector.getVoltageSupplier();
+ mEnergyConsumerIds = mConsumedEnergyRetriever.getEnergyConsumerIds(mEnergyConsumerType,
+ mEnergyConsumerName);
+
+ PersistableBundle extras = new PersistableBundle();
+ mLayout.toExtras(extras);
+ PowerStats.Descriptor powerStatsDescriptor = new PowerStats.Descriptor(
+ mPowerComponentId, mPowerComponentName, mLayout.getDeviceStatsArrayLength(),
+ null, 0, mLayout.getUidStatsArrayLength(),
+ extras);
+ mPowerStats = new PowerStats(powerStatsDescriptor);
+
+ mIsInitialized = true;
+ return true;
+ }
+
+ @Override
+ protected PowerStats collectStats() {
+ if (!ensureInitialized()) {
+ return null;
+ }
+
+ if (mEnergyConsumerIds.length == 0) {
+ return null;
+ }
+
+ long consumedEnergy = 0;
+ int voltageMv = mVoltageSupplier.getAsInt();
+ if (voltageMv <= 0) {
+ Slog.wtf(TAG, "Unexpected battery voltage (" + voltageMv
+ + " mV) when querying energy consumers");
+ } else {
+ long[] energyUws = mConsumedEnergyRetriever.getConsumedEnergyUws(mEnergyConsumerIds);
+ if (energyUws != null) {
+ for (int i = energyUws.length - 1; i >= 0; i--) {
+ if (energyUws[i] != ENERGY_UNSPECIFIED) {
+ consumedEnergy += energyUws[i];
+ }
+ }
+ }
+ }
+
+ long energyDelta = mLastConsumedEnergyUws != ENERGY_UNSPECIFIED
+ ? consumedEnergy - mLastConsumedEnergyUws : 0;
+ mLastConsumedEnergyUws = consumedEnergy;
+ if (energyDelta < 0) {
+ // Likely, restart of powerstats HAL
+ energyDelta = 0;
+ }
+
+ if (energyDelta == 0 && !mFirstCollection) {
+ return null;
+ }
+
+ int averageVoltage = mLastVoltageMv != 0 ? (mLastVoltageMv + voltageMv) / 2 : voltageMv;
+ mLastVoltageMv = voltageMv;
+ mLayout.setConsumedEnergy(mPowerStats.stats, 0, uJtoUc(energyDelta, averageVoltage));
+ long timestamp = mClock.elapsedRealtime();
+ mPowerStats.durationMs = timestamp - mLastUpdateTimestamp;
+ mLastUpdateTimestamp = timestamp;
+ mFirstCollection = false;
+ return mPowerStats;
+ }
+}
diff --git a/services/core/java/com/android/server/power/stats/GnssPowerStatsCollector.java b/services/core/java/com/android/server/power/stats/GnssPowerStatsCollector.java
new file mode 100644
index 0000000..168a874
--- /dev/null
+++ b/services/core/java/com/android/server/power/stats/GnssPowerStatsCollector.java
@@ -0,0 +1,30 @@
+/*
+ * 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.power.stats;
+
+import android.hardware.power.stats.EnergyConsumerType;
+import android.os.BatteryConsumer;
+
+public class GnssPowerStatsCollector extends EnergyConsumerPowerStatsCollector {
+
+ GnssPowerStatsCollector(Injector injector) {
+ super(injector, BatteryConsumer.POWER_COMPONENT_GNSS,
+ BatteryConsumer.powerComponentIdToString(BatteryConsumer.POWER_COMPONENT_GNSS),
+ EnergyConsumerType.GNSS, /* energy consumer name */ null,
+ new GnssPowerStatsLayout());
+ }
+}
diff --git a/services/core/java/com/android/server/power/stats/GnssPowerStatsLayout.java b/services/core/java/com/android/server/power/stats/GnssPowerStatsLayout.java
new file mode 100644
index 0000000..9a1317d
--- /dev/null
+++ b/services/core/java/com/android/server/power/stats/GnssPowerStatsLayout.java
@@ -0,0 +1,65 @@
+/*
+ * 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.power.stats;
+
+import android.location.GnssSignalQuality;
+import android.os.PersistableBundle;
+
+class GnssPowerStatsLayout extends BinaryStatePowerStatsLayout {
+ private static final String EXTRA_DEVICE_TIME_SIGNAL_LEVEL_POSITION = "dt-sig";
+ private static final String EXTRA_UID_TIME_SIGNAL_LEVEL_POSITION = "ut-sig";
+
+ private int mDeviceSignalLevelTimePosition;
+ private int mUidSignalLevelTimePosition;
+
+ GnssPowerStatsLayout() {
+ mDeviceSignalLevelTimePosition = addDeviceSection(
+ GnssSignalQuality.NUM_GNSS_SIGNAL_QUALITY_LEVELS, "level");
+ mUidSignalLevelTimePosition = addUidSection(
+ GnssSignalQuality.NUM_GNSS_SIGNAL_QUALITY_LEVELS, "level");
+ }
+
+ @Override
+ public void fromExtras(PersistableBundle extras) {
+ super.fromExtras(extras);
+ mDeviceSignalLevelTimePosition = extras.getInt(EXTRA_DEVICE_TIME_SIGNAL_LEVEL_POSITION);
+ mUidSignalLevelTimePosition = extras.getInt(EXTRA_UID_TIME_SIGNAL_LEVEL_POSITION);
+ }
+
+ @Override
+ public void toExtras(PersistableBundle extras) {
+ super.toExtras(extras);
+ extras.putInt(EXTRA_DEVICE_TIME_SIGNAL_LEVEL_POSITION, mDeviceSignalLevelTimePosition);
+ extras.putInt(EXTRA_UID_TIME_SIGNAL_LEVEL_POSITION, mUidSignalLevelTimePosition);
+ }
+
+ public void setDeviceSignalLevelTime(long[] stats, int signalLevel, long durationMillis) {
+ stats[mDeviceSignalLevelTimePosition + signalLevel] = durationMillis;
+ }
+
+ public long getDeviceSignalLevelTime(long[] stats, int signalLevel) {
+ return stats[mDeviceSignalLevelTimePosition + signalLevel];
+ }
+
+ public void setUidSignalLevelTime(long[] stats, int signalLevel, long durationMillis) {
+ stats[mUidSignalLevelTimePosition + signalLevel] = durationMillis;
+ }
+
+ public long getUidSignalLevelTime(long[] stats, int signalLevel) {
+ return stats[mUidSignalLevelTimePosition + signalLevel];
+ }
+}
diff --git a/services/core/java/com/android/server/power/stats/GnssPowerStatsProcessor.java b/services/core/java/com/android/server/power/stats/GnssPowerStatsProcessor.java
new file mode 100644
index 0000000..572bde9
--- /dev/null
+++ b/services/core/java/com/android/server/power/stats/GnssPowerStatsProcessor.java
@@ -0,0 +1,143 @@
+/*
+ * 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.power.stats;
+
+import android.location.GnssSignalQuality;
+import android.os.BatteryConsumer;
+import android.os.BatteryStats;
+import android.os.Process;
+
+import com.android.internal.os.PowerProfile;
+import com.android.internal.os.PowerStats;
+
+import java.util.Arrays;
+
+public class GnssPowerStatsProcessor extends BinaryStatePowerStatsProcessor {
+ private int mGnssSignalLevel = GnssSignalQuality.GNSS_SIGNAL_QUALITY_UNKNOWN;
+ private long mGnssSignalLevelTimestamp;
+ private final long[] mGnssSignalDurations =
+ new long[GnssSignalQuality.NUM_GNSS_SIGNAL_QUALITY_LEVELS];
+ private static final GnssPowerStatsLayout sStatsLayout = new GnssPowerStatsLayout();
+ private final UsageBasedPowerEstimator[] mSignalLevelEstimators =
+ new UsageBasedPowerEstimator[GnssSignalQuality.NUM_GNSS_SIGNAL_QUALITY_LEVELS];
+ private final boolean mUseSignalLevelEstimators;
+ private long[] mTmpDeviceStatsArray;
+
+ public GnssPowerStatsProcessor(PowerProfile powerProfile, PowerStatsUidResolver uidResolver) {
+ super(BatteryConsumer.POWER_COMPONENT_GNSS, uidResolver,
+ powerProfile.getAveragePower(PowerProfile.POWER_GPS_ON),
+ sStatsLayout);
+
+ boolean useSignalLevelEstimators = false;
+ for (int level = 0; level < GnssSignalQuality.NUM_GNSS_SIGNAL_QUALITY_LEVELS; level++) {
+ double power = powerProfile.getAveragePower(
+ PowerProfile.POWER_GPS_SIGNAL_QUALITY_BASED, level);
+ if (power != 0) {
+ useSignalLevelEstimators = true;
+ }
+ mSignalLevelEstimators[level] = new UsageBasedPowerEstimator(power);
+ }
+ mUseSignalLevelEstimators = useSignalLevelEstimators;
+ }
+
+ @Override
+ protected @BinaryState int getBinaryState(BatteryStats.HistoryItem item) {
+ if ((item.states & BatteryStats.HistoryItem.STATE_GPS_ON_FLAG) == 0) {
+ mGnssSignalLevel = GnssSignalQuality.GNSS_SIGNAL_QUALITY_UNKNOWN;
+ return STATE_OFF;
+ }
+
+ noteGnssSignalLevel(item);
+ return STATE_ON;
+ }
+
+ private void noteGnssSignalLevel(BatteryStats.HistoryItem item) {
+ int signalLevel = (item.states2 & BatteryStats.HistoryItem.STATE2_GPS_SIGNAL_QUALITY_MASK)
+ >> BatteryStats.HistoryItem.STATE2_GPS_SIGNAL_QUALITY_SHIFT;
+ if (signalLevel >= GnssSignalQuality.NUM_GNSS_SIGNAL_QUALITY_LEVELS) {
+ signalLevel = GnssSignalQuality.GNSS_SIGNAL_QUALITY_UNKNOWN;
+ }
+ if (signalLevel == mGnssSignalLevel) {
+ return;
+ }
+
+ if (mGnssSignalLevel != GnssSignalQuality.GNSS_SIGNAL_QUALITY_UNKNOWN) {
+ mGnssSignalDurations[mGnssSignalLevel] += item.time - mGnssSignalLevelTimestamp;
+ }
+ mGnssSignalLevel = signalLevel;
+ mGnssSignalLevelTimestamp = item.time;
+ }
+
+ @Override
+ protected void recordUsageDuration(PowerStats powerStats, int uid, long time) {
+ super.recordUsageDuration(powerStats, uid, time);
+
+ if (mGnssSignalLevel != GnssSignalQuality.GNSS_SIGNAL_QUALITY_UNKNOWN) {
+ mGnssSignalDurations[mGnssSignalLevel] += time - mGnssSignalLevelTimestamp;
+ } else if (mUseSignalLevelEstimators) {
+ // Default GNSS signal quality to GOOD for the purposes of power attribution
+ mGnssSignalDurations[GnssSignalQuality.GNSS_SIGNAL_QUALITY_GOOD] +=
+ time - mGnssSignalLevelTimestamp;
+ }
+
+ for (int level = 0; level < GnssSignalQuality.NUM_GNSS_SIGNAL_QUALITY_LEVELS; level++) {
+ long duration = mGnssSignalDurations[level];
+ sStatsLayout.setDeviceSignalLevelTime(powerStats.stats, level, duration);
+ if (uid != Process.INVALID_UID) {
+ long[] uidStats = powerStats.uidStats.get(uid);
+ if (uidStats == null) {
+ uidStats = new long[powerStats.descriptor.uidStatsArrayLength];
+ powerStats.uidStats.put(uid, uidStats);
+ sStatsLayout.setUidSignalLevelTime(uidStats, level, duration);
+ } else {
+ sStatsLayout.setUidSignalLevelTime(uidStats, level,
+ sStatsLayout.getUidSignalLevelTime(uidStats, level) + duration);
+ }
+ }
+ }
+
+ mGnssSignalLevelTimestamp = time;
+ Arrays.fill(mGnssSignalDurations, 0);
+ }
+
+ protected void computeDevicePowerEstimates(PowerComponentAggregatedPowerStats stats,
+ PowerEstimationPlan plan, boolean energyConsumerSupported) {
+ if (!mUseSignalLevelEstimators || energyConsumerSupported) {
+ super.computeDevicePowerEstimates(stats, plan, energyConsumerSupported);
+ return;
+ }
+
+ if (mTmpDeviceStatsArray == null) {
+ mTmpDeviceStatsArray = new long[stats.getPowerStatsDescriptor().statsArrayLength];
+ }
+
+ for (int i = plan.deviceStateEstimations.size() - 1; i >= 0; i--) {
+ DeviceStateEstimation estimation = plan.deviceStateEstimations.get(i);
+ if (!stats.getDeviceStats(mTmpDeviceStatsArray, estimation.stateValues)) {
+ continue;
+ }
+
+ double power = 0;
+ for (int level = 0; level < GnssSignalQuality.NUM_GNSS_SIGNAL_QUALITY_LEVELS; level++) {
+ long duration = sStatsLayout.getDeviceSignalLevelTime(mTmpDeviceStatsArray, level);
+ power += mSignalLevelEstimators[level].calculatePower(duration);
+ }
+ sStatsLayout.setDevicePowerEstimate(mTmpDeviceStatsArray, power);
+ stats.setDeviceStats(estimation.stateValues, mTmpDeviceStatsArray);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/power/stats/PowerStatsCollector.java b/services/core/java/com/android/server/power/stats/PowerStatsCollector.java
index b82c021..d442c61 100644
--- a/services/core/java/com/android/server/power/stats/PowerStatsCollector.java
+++ b/services/core/java/com/android/server/power/stats/PowerStatsCollector.java
@@ -231,10 +231,14 @@
}
interface ConsumedEnergyRetriever {
- int[] getEnergyConsumerIds(@EnergyConsumerType int energyConsumerType);
+ int[] getEnergyConsumerIds(@EnergyConsumerType int energyConsumerType, String name);
@Nullable
long[] getConsumedEnergyUws(int[] energyConsumerIds);
+
+ default int[] getEnergyConsumerIds(@EnergyConsumerType int energyConsumerType) {
+ return getEnergyConsumerIds(energyConsumerType, null);
+ }
}
static class ConsumedEnergyRetrieverImpl implements ConsumedEnergyRetriever {
@@ -245,7 +249,7 @@
}
@Override
- public int[] getEnergyConsumerIds(int energyConsumerType) {
+ public int[] getEnergyConsumerIds(int energyConsumerType, String name) {
if (mPowerStatsInternal == null) {
return new int[0];
}
@@ -257,7 +261,8 @@
List<EnergyConsumer> energyConsumers = new ArrayList<>();
for (EnergyConsumer energyConsumer : energyConsumerInfo) {
- if (energyConsumer.type == energyConsumerType) {
+ if (energyConsumer.type == energyConsumerType
+ && (name == null || name.equals(energyConsumer.name))) {
energyConsumers.add(energyConsumer);
}
}
diff --git a/services/core/java/com/android/server/powerstats/Android.bp b/services/core/java/com/android/server/powerstats/Android.bp
new file mode 100644
index 0000000..7f3b091
--- /dev/null
+++ b/services/core/java/com/android/server/powerstats/Android.bp
@@ -0,0 +1,11 @@
+aconfig_declarations {
+ name: "powerstats_flags",
+ package: "com.android.server.powerstats",
+ container: "system",
+ srcs: ["*.aconfig"],
+}
+
+java_aconfig_library {
+ name: "powerstats_flags_lib",
+ aconfig_declarations: "powerstats_flags",
+}
diff --git a/services/core/java/com/android/server/powerstats/TimerTrigger.java b/services/core/java/com/android/server/powerstats/TimerTrigger.java
index f8a4135..817a40d 100644
--- a/services/core/java/com/android/server/powerstats/TimerTrigger.java
+++ b/services/core/java/com/android/server/powerstats/TimerTrigger.java
@@ -16,8 +16,10 @@
package com.android.server.powerstats;
+import android.app.AlarmManager;
import android.content.Context;
import android.os.Handler;
+import android.os.SystemClock;
import android.util.Slog;
/**
@@ -33,37 +35,53 @@
private static final long LOG_PERIOD_MS_HIGH_FREQUENCY = 2 * 60 * 1000; // 2 minutes
private final Handler mHandler;
+ private final AlarmManager mAlarmManager;
- private Runnable mLogDataLowFrequency = new Runnable() {
+ class PeriodicTimer implements Runnable, AlarmManager.OnAlarmListener {
+ private final String mName;
+ private final long mPeriodMs;
+ private final int mMsgType;
+
+ PeriodicTimer(String name, long periodMs, int msgType) {
+ mName = name;
+ mPeriodMs = periodMs;
+ mMsgType = msgType;
+ }
+
+ @Override
+ public void onAlarm() {
+ run();
+ }
+
@Override
public void run() {
- // Do not wake the device for these messages. Opportunistically log rail data every
- // LOG_PERIOD_MS_LOW_FREQUENCY.
- mHandler.postDelayed(mLogDataLowFrequency, LOG_PERIOD_MS_LOW_FREQUENCY);
- if (DEBUG) Slog.d(TAG, "Received delayed message. Log rail data low frequency");
- logPowerStatsData(PowerStatsLogger.MSG_LOG_TO_DATA_STORAGE_LOW_FREQUENCY);
+ if (Flags.alarmBasedPowerstatsLogging()) {
+ final long nextAlarmMs = SystemClock.elapsedRealtime() + mPeriodMs;
+ mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, nextAlarmMs,
+ AlarmManager.WINDOW_EXACT, 0, mName, this, mHandler, null);
+ } else {
+ mHandler.postDelayed(this, mPeriodMs);
+ }
+ if (DEBUG) Slog.d(TAG, "Received delayed message (" + mName + "). Logging rail data");
+ logPowerStatsData(mMsgType);
}
- };
-
- private Runnable mLogDataHighFrequency = new Runnable() {
- @Override
- public void run() {
- // Do not wake the device for these messages. Opportunistically log rail data every
- // LOG_PERIOD_MS_HIGH_FREQUENCY.
- mHandler.postDelayed(mLogDataHighFrequency, LOG_PERIOD_MS_HIGH_FREQUENCY);
- if (DEBUG) Slog.d(TAG, "Received delayed message. Log rail data high frequency");
- logPowerStatsData(PowerStatsLogger.MSG_LOG_TO_DATA_STORAGE_HIGH_FREQUENCY);
- }
- };
+ }
public TimerTrigger(Context context, PowerStatsLogger powerStatsLogger,
boolean triggerEnabled) {
super(context, powerStatsLogger);
mHandler = mContext.getMainThreadHandler();
+ mAlarmManager = mContext.getSystemService(AlarmManager.class);
if (triggerEnabled) {
- mLogDataLowFrequency.run();
- mLogDataHighFrequency.run();
+ final PeriodicTimer logDataLowFrequency = new PeriodicTimer("PowerStatsLowFreqLog",
+ LOG_PERIOD_MS_LOW_FREQUENCY,
+ PowerStatsLogger.MSG_LOG_TO_DATA_STORAGE_LOW_FREQUENCY);
+ final PeriodicTimer logDataHighFrequency = new PeriodicTimer("PowerStatsHighFreqLog",
+ LOG_PERIOD_MS_HIGH_FREQUENCY,
+ PowerStatsLogger.MSG_LOG_TO_DATA_STORAGE_HIGH_FREQUENCY);
+ logDataLowFrequency.run();
+ logDataHighFrequency.run();
}
}
}
diff --git a/services/core/java/com/android/server/powerstats/flags.aconfig b/services/core/java/com/android/server/powerstats/flags.aconfig
new file mode 100644
index 0000000..0a4a751
--- /dev/null
+++ b/services/core/java/com/android/server/powerstats/flags.aconfig
@@ -0,0 +1,13 @@
+
+package: "com.android.server.powerstats"
+container: "system"
+
+flag {
+ name: "alarm_based_powerstats_logging"
+ namespace: "backstage_power"
+ description: "Utilize new OomAdjuster implementation"
+ bug: "294598168"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index 04db3e8..3138a9e 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -1870,6 +1870,11 @@
@Override
public boolean isInSignificantPlace() {
+ if (android.security.Flags.significantPlaces()) {
+ mSignificantPlaceServiceWatcher.runOnBinder(
+ binder -> ISignificantPlaceProvider.Stub.asInterface(binder)
+ .onSignificantPlaceCheck());
+ }
return mIsInSignificantPlace;
}
diff --git a/services/core/java/com/android/server/tv/TvInputHardwareManager.java b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
old mode 100755
new mode 100644
diff --git a/services/core/java/com/android/server/vibrator/VibratorController.java b/services/core/java/com/android/server/vibrator/VibratorController.java
index 6710d02..988e8fe 100644
--- a/services/core/java/com/android/server/vibrator/VibratorController.java
+++ b/services/core/java/com/android/server/vibrator/VibratorController.java
@@ -56,10 +56,17 @@
private volatile boolean mIsUnderExternalControl;
private volatile float mCurrentAmplitude;
- /** Listener for vibration completion callbacks from native. */
+ /**
+ * Listener for vibration completion callbacks from native.
+ *
+ * <p>Only the latest active native call to {@link VibratorController#on} will ever trigger this
+ * completion callback, to avoid race conditions during a vibration playback. If a new call to
+ * {@link #on} or {@link #off} happens before a previous callback was triggered then the
+ * previous callback will be disabled, even if the new command fails.
+ */
public interface OnVibrationCompleteListener {
- /** Callback triggered when vibration is complete. */
+ /** Callback triggered when an active vibration command is complete. */
void onComplete(int vibratorId, long vibrationId);
}
@@ -235,7 +242,7 @@
}
/**
- * Turn on the vibrator for {@code milliseconds} time, using {@code vibrationId} or completion
+ * Turn on the vibrator for {@code milliseconds} time, using {@code vibrationId} for completion
* callback to {@link OnVibrationCompleteListener}.
*
* <p>This will affect the state of {@link #isVibrating()}.
@@ -255,7 +262,7 @@
}
/**
- * Plays predefined vibration effect, using {@code vibrationId} or completion callback to
+ * Plays predefined vibration effect, using {@code vibrationId} for completion callback to
* {@link OnVibrationCompleteListener}.
*
* <p>This will affect the state of {@link #isVibrating()}.
@@ -276,8 +283,8 @@
}
/**
- * Plays a composition of vibration primitives, using {@code vibrationId} or completion callback
- * to {@link OnVibrationCompleteListener}.
+ * Plays a composition of vibration primitives, using {@code vibrationId} for completion
+ * callback to {@link OnVibrationCompleteListener}.
*
* <p>This will affect the state of {@link #isVibrating()}.
*
@@ -299,7 +306,7 @@
}
/**
- * Plays a composition of pwle primitives, using {@code vibrationId} or completion callback
+ * Plays a composition of pwle primitives, using {@code vibrationId} for completion callback
* to {@link OnVibrationCompleteListener}.
*
* <p>This will affect the state of {@link #isVibrating()}.
@@ -321,7 +328,11 @@
}
}
- /** Turns off the vibrator. This will affect the state of {@link #isVibrating()}. */
+ /**
+ * Turns off the vibrator and disables completion callback to any pending vibration.
+ *
+ * <p>This will affect the state of {@link #isVibrating()}.
+ */
public void off() {
synchronized (mLock) {
mNativeWrapper.off();
diff --git a/services/core/java/com/android/server/wm/ActivityClientController.java b/services/core/java/com/android/server/wm/ActivityClientController.java
index c9395da..3e177c9 100644
--- a/services/core/java/com/android/server/wm/ActivityClientController.java
+++ b/services/core/java/com/android/server/wm/ActivityClientController.java
@@ -1299,9 +1299,11 @@
// The restore windowing mode must be set after the windowing mode is set since
// Task#setWindowingMode resets the restore windowing mode to WINDOWING_MODE_INVALID.
requester.mMultiWindowRestoreWindowingMode = restoreWindowingMode;
+ requester.mMultiWindowRestoreParent =
+ requester.getParent().mRemoteToken.toWindowContainerToken();
} else {
targetWindowingMode = requester.mMultiWindowRestoreWindowingMode;
- requester.setWindowingMode(targetWindowingMode);
+ requester.restoreWindowingMode();
}
if (targetWindowingMode == WINDOWING_MODE_FULLSCREEN) {
requester.setBounds(null);
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index fec1af4..78a6816 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -661,7 +661,8 @@
*/
private CompatDisplayInsets mCompatDisplayInsets;
- private final TaskFragment.ConfigOverrideHint mResolveConfigHint;
+ @VisibleForTesting
+ final TaskFragment.ConfigOverrideHint mResolveConfigHint;
private final boolean mOptOutEdgeToEdge;
@@ -4032,6 +4033,10 @@
if (next == null) {
mRootWindowContainer.ensureVisibilityAndConfig(null /* starting */, mDisplayContent,
true /* deferResume */);
+ if (mDisplayContent.topRunningActivity() == null) {
+ // The transition is ready on a display with no running activities.
+ mTransitionController.setReady(mDisplayContent);
+ }
}
if (activityRemoved) {
mRootWindowContainer.resumeFocusedTasksTopActivities();
@@ -6547,7 +6552,10 @@
// Schedule an idle timeout in case the app doesn't do it for us.
mTaskSupervisor.scheduleIdleTimeout(this);
- mTaskSupervisor.reportResumedActivityLocked(this);
+ mTaskSupervisor.mStoppingActivities.remove(this);
+ if (getDisplayArea().allResumedActivitiesComplete()) {
+ mRootWindowContainer.executeAppTransitionForAllDisplay();
+ }
resumeKeyDispatchingLocked();
final Task rootTask = getRootTask();
@@ -8533,6 +8541,8 @@
mIsEligibleForFixedOrientationLetterbox = false;
mLetterboxBoundsForFixedOrientationAndAspectRatio = null;
mLetterboxBoundsForAspectRatio = null;
+ mResolveConfigHint.resolveTmpOverrides(mDisplayContent, newParentConfiguration,
+ isFixedRotationTransforming());
// Can't use resolvedConfig.windowConfiguration.getWindowingMode() because it can be
// different from windowing mode of the task (PiP) during transition from fullscreen to PiP
@@ -8647,10 +8657,15 @@
}
applySizeOverrideIfNeeded(newParentConfiguration, parentWindowingMode, resolvedConfig);
+ mResolveConfigHint.resetTmpOverrides();
logAppCompatState();
}
+ @Nullable Rect getParentAppBoundsOverride() {
+ return Rect.copyOrNull(mResolveConfigHint.mTmpParentAppBoundsOverride);
+ }
+
/**
* If necessary, override configuration fields related to app bounds.
* This will happen when the app is targeting SDK earlier than 35.
@@ -8674,8 +8689,8 @@
rotation = mDisplayContent.getRotation();
}
if (!mOptOutEdgeToEdge && (!mResolveConfigHint.mUseOverrideInsetsForConfig
- || getCompatDisplayInsets() != null || shouldCreateCompatDisplayInsets()
- || isFloating(parentWindowingMode) || rotation == ROTATION_UNDEFINED)) {
+ || getCompatDisplayInsets() != null || isFloating(parentWindowingMode)
+ || rotation == ROTATION_UNDEFINED)) {
// If the insets configuration decoupled logic is not enabled for the app, or the app
// already has a compat override, or the context doesn't contain enough info to
// calculate the override, skip the override.
@@ -8697,7 +8712,7 @@
: mDisplayContent.mBaseDisplayWidth;
final int dh = rotated ? mDisplayContent.mBaseDisplayWidth
: mDisplayContent.mBaseDisplayHeight;
- final Rect nonDecorInsets = mDisplayContent.getDisplayPolicy()
+ final Rect nonDecorInsets = mDisplayContent.getDisplayPolicy()
.getDecorInsetsInfo(rotation, dw, dh).mOverrideNonDecorInsets;
// This should be the only place override the configuration for ActivityRecord. Override
// the value if not calculated yet.
@@ -8713,12 +8728,10 @@
}
density *= DisplayMetrics.DENSITY_DEFAULT_SCALE;
if (inOutConfig.screenWidthDp == Configuration.SCREEN_WIDTH_DP_UNDEFINED) {
- final int overrideScreenWidthDp = (int) (outAppBounds.width() / density + 0.5f);
- inOutConfig.screenWidthDp = overrideScreenWidthDp;
+ inOutConfig.screenWidthDp = (int) (outAppBounds.width() / density + 0.5f);
}
if (inOutConfig.screenHeightDp == Configuration.SCREEN_HEIGHT_DP_UNDEFINED) {
- final int overrideScreenHeightDp = (int) (outAppBounds.height() / density + 0.5f);
- inOutConfig.screenHeightDp = overrideScreenHeightDp;
+ inOutConfig.screenHeightDp = (int) (outAppBounds.height() / density + 0.5f);
}
if (inOutConfig.smallestScreenWidthDp
== Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED
@@ -8829,7 +8842,7 @@
}
final Rect screenResolvedBounds =
mSizeCompatBounds != null ? mSizeCompatBounds : resolvedBounds;
- final Rect parentAppBounds = newParentConfiguration.windowConfiguration.getAppBounds();
+ final Rect parentAppBounds = mResolveConfigHint.mTmpParentAppBoundsOverride;
final Rect parentBounds = newParentConfiguration.windowConfiguration.getBounds();
final float screenResolvedBoundsWidth = screenResolvedBounds.width();
final float parentAppBoundsWidth = parentAppBounds.width();
@@ -9238,7 +9251,7 @@
*/
private void resolveAspectRatioRestriction(Configuration newParentConfiguration) {
final Configuration resolvedConfig = getResolvedOverrideConfiguration();
- final Rect parentAppBounds = newParentConfiguration.windowConfiguration.getAppBounds();
+ final Rect parentAppBounds = mResolveConfigHint.mTmpParentAppBoundsOverride;
final Rect parentBounds = newParentConfiguration.windowConfiguration.getBounds();
final Rect resolvedBounds = resolvedConfig.windowConfiguration.getBounds();
// Use tmp bounds to calculate aspect ratio so we can know whether the activity should use
@@ -9267,19 +9280,6 @@
@NonNull CompatDisplayInsets compatDisplayInsets) {
final Configuration resolvedConfig = getResolvedOverrideConfiguration();
final Rect resolvedBounds = resolvedConfig.windowConfiguration.getBounds();
- final Insets insets;
- if (mResolveConfigHint.mUseOverrideInsetsForConfig) {
- // TODO(b/343197837): Add test to verify SCM behaviour with new bound configuration
- // Insets are decoupled from configuration by default from V+, use legacy
- // compatibility behaviour for apps targeting SDK earlier than 35
- // (see applySizeOverrideIfNeeded).
- insets = Insets.of(mDisplayContent.getDisplayPolicy()
- .getDecorInsetsInfo(mDisplayContent.mDisplayFrames.mRotation,
- mDisplayContent.mDisplayFrames.mWidth,
- mDisplayContent.mDisplayFrames.mHeight).mOverrideNonDecorInsets);
- } else {
- insets = Insets.NONE;
- }
// When an activity needs to be letterboxed because of fixed orientation, use fixed
// orientation bounds (stored in resolved bounds) instead of parent bounds since the
@@ -9290,22 +9290,22 @@
final Rect containerBounds = useResolvedBounds
? new Rect(resolvedBounds)
: newParentConfiguration.windowConfiguration.getBounds();
- final Rect parentAppBounds =
- newParentConfiguration.windowConfiguration.getAppBounds();
- parentAppBounds.inset(insets);
final Rect containerAppBounds = useResolvedBounds
? new Rect(resolvedConfig.windowConfiguration.getAppBounds())
- : parentAppBounds;
+ : mResolveConfigHint.mTmpParentAppBoundsOverride;
final int requestedOrientation = getRequestedConfigurationOrientation();
final boolean orientationRequested = requestedOrientation != ORIENTATION_UNDEFINED;
+ final int parentOrientation = mResolveConfigHint.mUseOverrideInsetsForConfig
+ ? mResolveConfigHint.mTmpOverrideConfigOrientation
+ : newParentConfiguration.orientation;
final int orientation = orientationRequested
? requestedOrientation
// We should use the original orientation of the activity when possible to avoid
// forcing the activity in the opposite orientation.
: compatDisplayInsets.mOriginalRequestedOrientation != ORIENTATION_UNDEFINED
? compatDisplayInsets.mOriginalRequestedOrientation
- : newParentConfiguration.orientation;
+ : parentOrientation;
int rotation = newParentConfiguration.windowConfiguration.getRotation();
final boolean isFixedToUserRotation = mDisplayContent == null
|| mDisplayContent.getDisplayRotation().isFixedToUserRotation();
@@ -9347,7 +9347,7 @@
// Use parent orientation if it cannot be decided by bounds, so the activity can fit inside
// the parent bounds appropriately.
if (resolvedConfig.screenWidthDp == resolvedConfig.screenHeightDp) {
- resolvedConfig.orientation = newParentConfiguration.orientation;
+ resolvedConfig.orientation = parentOrientation;
}
// Below figure is an example that puts an activity which was launched in a larger container
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index d7a696f..e6d8132 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -139,6 +139,7 @@
import com.android.server.wm.BackgroundActivityStartController.BalVerdict;
import com.android.server.wm.LaunchParamsController.LaunchParams;
import com.android.server.wm.TaskFragment.EmbeddingCheckResult;
+import com.android.wm.shell.Flags;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
@@ -1723,7 +1724,14 @@
// Get top task at beginning because the order may be changed when reusing existing task.
final Task prevTopRootTask = mPreferredTaskDisplayArea.getFocusedRootTask();
final Task prevTopTask = prevTopRootTask != null ? prevTopRootTask.getTopLeafTask() : null;
- final Task reusedTask = resolveReusableTask();
+ final boolean sourceActivityLaunchedFromBubble =
+ sourceRecord != null && sourceRecord.getLaunchedFromBubble();
+ // if the flag is enabled, allow reusing bubbled tasks only if the source activity is
+ // bubbled.
+ final boolean includeLaunchedFromBubble =
+ Flags.onlyReuseBubbledTaskWhenLaunchedFromBubble()
+ ? sourceActivityLaunchedFromBubble : true;
+ final Task reusedTask = resolveReusableTask(includeLaunchedFromBubble);
// If requested, freeze the task list
if (mOptions != null && mOptions.freezeRecentTasksReordering()
@@ -2722,8 +2730,11 @@
/**
* Decide whether the new activity should be inserted into an existing task. Returns null
* if not or an ActivityRecord with the task into which the new activity should be added.
+ *
+ * @param includeLaunchedFromBubble whether a task whose top activity was launched from a bubble
+ * should be allowed to be reused for the new activity.
*/
- private Task resolveReusableTask() {
+ private Task resolveReusableTask(boolean includeLaunchedFromBubble) {
// If a target task is specified, try to reuse that one
if (mOptions != null && mOptions.getLaunchTaskId() != INVALID_TASK_ID) {
Task launchTask = mRootWindowContainer.anyTaskForId(mOptions.getLaunchTaskId());
@@ -2767,7 +2778,8 @@
} else {
// Otherwise find the best task to put the activity in.
intentActivity =
- mRootWindowContainer.findTask(mStartActivity, mPreferredTaskDisplayArea);
+ mRootWindowContainer.findTask(mStartActivity, mPreferredTaskDisplayArea,
+ includeLaunchedFromBubble);
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
index 3867d2d..b6e6991 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
@@ -2064,21 +2064,6 @@
}
}
- boolean reportResumedActivityLocked(ActivityRecord r) {
- // A resumed activity cannot be stopping. remove from list
- mStoppingActivities.remove(r);
-
- final Task rootTask = r.getRootTask();
- if (rootTask.getDisplayArea().allResumedActivitiesComplete()) {
- mRootWindowContainer.ensureActivitiesVisible();
- // Make sure activity & window visibility should be identical
- // for all displays in this stage.
- mRootWindowContainer.executeAppTransitionForAllDisplay();
- return true;
- }
- return false;
- }
-
// Called when WindowManager has finished animating the launchingBehind activity to the back.
private void handleLaunchTaskBehindCompleteLocked(ActivityRecord r) {
final Task task = r.getTask();
diff --git a/services/core/java/com/android/server/wm/BackNavigationController.java b/services/core/java/com/android/server/wm/BackNavigationController.java
index f91ef1d..0febec9 100644
--- a/services/core/java/com/android/server/wm/BackNavigationController.java
+++ b/services/core/java/com/android/server/wm/BackNavigationController.java
@@ -200,6 +200,7 @@
}
infoBuilder.setOnBackInvokedCallback(callbackInfo.getCallback());
infoBuilder.setAnimationCallback(callbackInfo.isAnimationCallback());
+ infoBuilder.setTouchableRegion(window.getFrame());
mNavigationMonitor.startMonitor(window, navigationObserver);
ProtoLog.d(WM_DEBUG_BACK_PREVIEW, "startBackNavigation currentTask=%s, "
diff --git a/services/core/java/com/android/server/wm/EmbeddedWindowController.java b/services/core/java/com/android/server/wm/EmbeddedWindowController.java
index 0978cb4..a21ba26 100644
--- a/services/core/java/com/android/server/wm/EmbeddedWindowController.java
+++ b/services/core/java/com/android/server/wm/EmbeddedWindowController.java
@@ -77,12 +77,14 @@
mWindows.put(inputToken, window);
final InputTransferToken inputTransferToken = window.getInputTransferToken();
mWindowsByInputTransferToken.put(inputTransferToken, window);
- mWindowsByWindowToken.put(window.getWindowToken(), window);
+ final IBinder windowToken = window.getWindowToken();
+ mWindowsByWindowToken.put(windowToken, window);
updateProcessController(window);
window.mClient.linkToDeath(()-> {
synchronized (mGlobalLock) {
mWindows.remove(inputToken);
mWindowsByInputTransferToken.remove(inputTransferToken);
+ mWindowsByWindowToken.remove(windowToken);
}
}, 0);
} catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index c683d4d..f70d2a5 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -538,13 +538,6 @@
|| !mWindowManager.isKeyguardSecure(mService.getCurrentUserId());
}
- /**
- * @return Whether the dream activity is on top of default display.
- */
- boolean isShowingDream() {
- return getDisplayState(DEFAULT_DISPLAY).mShowingDream;
- }
-
private void updateKeyguardSleepToken() {
for (int displayNdx = mRootWindowContainer.getChildCount() - 1;
displayNdx >= 0; displayNdx--) {
@@ -631,7 +624,6 @@
* Note that this can be true even if the keyguard is disabled or not showing.
*/
private boolean mOccluded;
- private boolean mShowingDream;
private ActivityRecord mTopOccludesActivity;
private ActivityRecord mDismissingKeyguardActivity;
@@ -669,7 +661,6 @@
mRequestDismissKeyguard = false;
mOccluded = false;
- mShowingDream = false;
mTopOccludesActivity = null;
mDismissingKeyguardActivity = null;
@@ -697,21 +688,18 @@
// Only the top activity may control occluded, as we can't occlude the Keyguard
// if the top app doesn't want to occlude it.
- occludedByActivity = mTopOccludesActivity != null
+ mOccluded = mTopOccludesActivity != null
|| (mDismissingKeyguardActivity != null
&& task.topRunningActivity() == mDismissingKeyguardActivity
&& controller.canShowWhileOccluded(
true /* dismissKeyguard */, false /* showWhenLocked */));
// FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD only apply for secondary display.
if (mDisplayId != DEFAULT_DISPLAY) {
- occludedByActivity |= display.canShowWithInsecureKeyguard()
+ mOccluded |= display.canShowWithInsecureKeyguard()
&& controller.canDismissKeyguard();
}
}
- mShowingDream = display.getDisplayPolicy().isShowingDreamLw() && (top != null
- && top.getActivityType() == ACTIVITY_TYPE_DREAM);
- mOccluded = mShowingDream || occludedByActivity;
mRequestDismissKeyguard = lastDismissKeyguardActivity != mDismissingKeyguardActivity
&& !mOccluded && !mKeyguardGoingAway
&& mDismissingKeyguardActivity != null;
diff --git a/services/core/java/com/android/server/wm/LetterboxUiController.java b/services/core/java/com/android/server/wm/LetterboxUiController.java
index 194771f..5e93e89 100644
--- a/services/core/java/com/android/server/wm/LetterboxUiController.java
+++ b/services/core/java/com/android/server/wm/LetterboxUiController.java
@@ -1288,6 +1288,9 @@
if (!allowHorizontalReachabilityForThinLetterbox()) {
return false;
}
+ final Rect parentAppBoundsOverride = mActivityRecord.getParentAppBoundsOverride();
+ final Rect parentAppBounds = parentAppBoundsOverride != null
+ ? parentAppBoundsOverride : parentConfiguration.windowConfiguration.getAppBounds();
// Use screen resolved bounds which uses resolved bounds or size compat bounds
// as activity bounds can sometimes be empty
final Rect opaqueActivityBounds = mActivityRecord.mTransparentPolicy
@@ -1297,10 +1300,8 @@
&& parentConfiguration.windowConfiguration.getWindowingMode()
== WINDOWING_MODE_FULLSCREEN
// Check whether the activity fills the parent vertically.
- && parentConfiguration.windowConfiguration.getAppBounds().height()
- <= opaqueActivityBounds.height()
- && parentConfiguration.windowConfiguration.getAppBounds().width()
- > opaqueActivityBounds.width();
+ && parentAppBounds.height() <= opaqueActivityBounds.height()
+ && parentAppBounds.width() > opaqueActivityBounds.width();
}
@VisibleForTesting
@@ -1326,6 +1327,9 @@
if (!allowVerticalReachabilityForThinLetterbox()) {
return false;
}
+ final Rect parentAppBoundsOverride = mActivityRecord.getParentAppBoundsOverride();
+ final Rect parentAppBounds = parentAppBoundsOverride != null
+ ? parentAppBoundsOverride : parentConfiguration.windowConfiguration.getAppBounds();
// Use screen resolved bounds which uses resolved bounds or size compat bounds
// as activity bounds can sometimes be empty.
final Rect opaqueActivityBounds = mActivityRecord.mTransparentPolicy
@@ -1335,10 +1339,8 @@
&& parentConfiguration.windowConfiguration.getWindowingMode()
== WINDOWING_MODE_FULLSCREEN
// Check whether the activity fills the parent horizontally.
- && parentConfiguration.windowConfiguration.getAppBounds().width()
- <= opaqueActivityBounds.width()
- && parentConfiguration.windowConfiguration.getAppBounds().height()
- > opaqueActivityBounds.height();
+ && parentAppBounds.width() <= opaqueActivityBounds.width()
+ && parentAppBounds.height() > opaqueActivityBounds.height();
}
@VisibleForTesting
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 9c7c41c..54ba47e 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -314,13 +314,19 @@
private boolean isDocument;
private Uri documentData;
- void init(int activityType, String taskAffinity, Intent intent, ActivityInfo info) {
+ // determines whether to include bubbled tasks. defaults to true to preserve previous
+ // behavior.
+ private boolean mIncludeLaunchedFromBubble = true;
+
+ void init(int activityType, String taskAffinity, Intent intent, ActivityInfo info,
+ boolean includeLaunchedFromBubble) {
mActivityType = activityType;
mTaskAffinity = taskAffinity;
mIntent = intent;
mInfo = info;
mIdealRecord = null;
mCandidateRecord = null;
+ mIncludeLaunchedFromBubble = includeLaunchedFromBubble;
}
/**
@@ -362,7 +368,8 @@
}
// Overlays should not be considered as the task's logical top activity.
- final ActivityRecord r = task.getTopNonFinishingActivity(false /* includeOverlays */);
+ final ActivityRecord r = task.getTopNonFinishingActivity(
+ false /* includeOverlays */, mIncludeLaunchedFromBubble);
if (r == null || r.finishing || r.mUserId != userId
|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
@@ -1898,6 +1905,7 @@
// Don't do recursive work.
return;
}
+ Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "RWC_ensureActivitiesVisible");
mTaskSupervisor.beginActivityVisibilityUpdate();
try {
// First the front root tasks. In case any are not fullscreen and are in front of home.
@@ -1907,6 +1915,7 @@
}
} finally {
mTaskSupervisor.endActivityVisibilityUpdate();
+ Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
}
@@ -2370,18 +2379,20 @@
}
@Nullable
- ActivityRecord findTask(ActivityRecord r, TaskDisplayArea preferredTaskDisplayArea) {
+ ActivityRecord findTask(ActivityRecord r, TaskDisplayArea preferredTaskDisplayArea,
+ boolean includeLaunchedFromBubble) {
return findTask(r.getActivityType(), r.taskAffinity, r.intent, r.info,
- preferredTaskDisplayArea);
+ preferredTaskDisplayArea, includeLaunchedFromBubble);
}
@Nullable
ActivityRecord findTask(int activityType, String taskAffinity, Intent intent, ActivityInfo info,
- TaskDisplayArea preferredTaskDisplayArea) {
+ TaskDisplayArea preferredTaskDisplayArea, boolean includeLaunchedFromBubble) {
ProtoLog.d(WM_DEBUG_TASKS, "Looking for task of type=%s, taskAffinity=%s, intent=%s"
- + ", info=%s, preferredTDA=%s", activityType, taskAffinity, intent, info,
- preferredTaskDisplayArea);
- mTmpFindTaskResult.init(activityType, taskAffinity, intent, info);
+ + ", info=%s, preferredTDA=%s, includeLaunchedFromBubble=%b", activityType,
+ taskAffinity, intent, info, preferredTaskDisplayArea, includeLaunchedFromBubble);
+ mTmpFindTaskResult.init(activityType, taskAffinity, intent, info,
+ includeLaunchedFromBubble);
// Looking up task on preferred display area first
ActivityRecord candidateActivity = null;
diff --git a/services/core/java/com/android/server/wm/RunningTasks.java b/services/core/java/com/android/server/wm/RunningTasks.java
index 1cc1a57..7510180 100644
--- a/services/core/java/com/android/server/wm/RunningTasks.java
+++ b/services/core/java/com/android/server/wm/RunningTasks.java
@@ -157,7 +157,7 @@
// home & recent tasks
return;
}
- if (task.isVisible()) {
+ if (task.isVisibleRequested()) {
mTmpVisibleTasks.add(task);
} else {
mTmpInvisibleTasks.add(task);
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 13883fd..22f718d 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -445,6 +445,7 @@
int mPrevDisplayId = INVALID_DISPLAY;
int mMultiWindowRestoreWindowingMode = INVALID_WINDOWING_MODE;
+ WindowContainerToken mMultiWindowRestoreParent;
/**
* Last requested orientation reported to DisplayContent. This is different from {@link
@@ -4634,6 +4635,25 @@
return TASK;
}
+ /**
+ * Restores to the windowing mode saved when task requested to enter fullscreen using
+ * {@link Activity#requestFullscreenMode} API if it is valid. The task is also reparented to
+ * the previous parent if parent has changed.
+ */
+ void restoreWindowingMode() {
+ if (mMultiWindowRestoreWindowingMode == INVALID_WINDOWING_MODE) {
+ return;
+ }
+ if (!getParent().mRemoteToken.toWindowContainerToken()
+ .equals(mMultiWindowRestoreParent)) {
+ // Restore previous parent if parent has changed.
+ final Task parent = fromWindowContainerToken(mMultiWindowRestoreParent);
+ reparent(parent, MAX_VALUE);
+ }
+
+ setWindowingMode(mMultiWindowRestoreWindowingMode);
+ }
+
@Override
public void setWindowingMode(int windowingMode) {
// Calling Task#setWindowingMode() for leaf task since this is a specialization of
@@ -4766,6 +4786,12 @@
if (com.android.window.flags.Flags.removePrepareSurfaceInPlacement()
&& lastParentBeforePip.mSyncState == SYNC_STATE_NONE) {
lastParentBeforePip.prepareSurfaces();
+ // If the moveToFront is a part of finishing transition, then make sure
+ // the z-order of tasks are up-to-date.
+ if (topActivity.mTransitionController.inFinishingTransition(topActivity)) {
+ Transition.assignLayers(taskDisplayArea,
+ taskDisplayArea.getPendingTransaction());
+ }
}
}
if (isPip2ExperimentEnabled) {
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index b8b746a..ab72e3c 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -40,6 +40,8 @@
import static android.os.Process.SYSTEM_UID;
import static android.os.UserHandle.USER_NULL;
import static android.view.Display.INVALID_DISPLAY;
+import static android.view.Surface.ROTATION_270;
+import static android.view.Surface.ROTATION_90;
import static android.view.WindowManager.LayoutParams.FLAG_DIM_BEHIND;
import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManager.TRANSIT_FLAG_OPEN_BEHIND;
@@ -87,6 +89,7 @@
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
+import android.graphics.Insets;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.IBinder;
@@ -1101,21 +1104,34 @@
}
ActivityRecord getTopNonFinishingActivity() {
- return getTopNonFinishingActivity(true /* includeOverlays */);
+ return getTopNonFinishingActivity(
+ true /* includeOverlays */, true /* includeLaunchedFromBubble */);
}
/**
* Returns the top-most non-finishing activity, even if the activity is NOT ok to show to
* the current user.
* @param includeOverlays whether the task overlay activity should be included.
+ * @param includeLaunchedFromBubble whether activities that were launched from a bubble should
+ * be included.
* @see #topRunningActivity(boolean)
*/
- ActivityRecord getTopNonFinishingActivity(boolean includeOverlays) {
- // Split into 2 to avoid object creation due to variable capture.
+ ActivityRecord getTopNonFinishingActivity(boolean includeOverlays,
+ boolean includeLaunchedFromBubble) {
+ // Split to avoid object creation due to variable capture.
if (includeOverlays) {
- return getActivity((r) -> !r.finishing);
+ if (includeLaunchedFromBubble) {
+ return getActivity(r -> !r.finishing);
+ } else {
+ return getActivity(r -> !r.finishing && !r.getLaunchedFromBubble());
+ }
}
- return getActivity((r) -> !r.finishing && !r.isTaskOverlay());
+ if (includeLaunchedFromBubble) {
+ return getActivity(r -> !r.finishing && !r.isTaskOverlay());
+ } else {
+ return getActivity(
+ r -> !r.finishing && !r.isTaskOverlay() && !r.getLaunchedFromBubble());
+ }
}
ActivityRecord topRunningActivity() {
@@ -2225,7 +2241,43 @@
static class ConfigOverrideHint {
@Nullable DisplayInfo mTmpOverrideDisplayInfo;
@Nullable ActivityRecord.CompatDisplayInsets mTmpCompatInsets;
+ @Nullable Rect mTmpParentAppBoundsOverride;
+ int mTmpOverrideConfigOrientation;
boolean mUseOverrideInsetsForConfig;
+
+ void resolveTmpOverrides(DisplayContent dc, Configuration parentConfig,
+ boolean isFixedRotationTransforming) {
+ mTmpParentAppBoundsOverride = new Rect(parentConfig.windowConfiguration.getAppBounds());
+ final Insets insets;
+ if (mUseOverrideInsetsForConfig && dc != null) {
+ // Insets are decoupled from configuration by default from V+, use legacy
+ // compatibility behaviour for apps targeting SDK earlier than 35
+ // (see applySizeOverrideIfNeeded).
+ int rotation = parentConfig.windowConfiguration.getRotation();
+ if (rotation == ROTATION_UNDEFINED && !isFixedRotationTransforming) {
+ rotation = dc.getRotation();
+ }
+ final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270);
+ final int dw = rotated ? dc.mBaseDisplayHeight : dc.mBaseDisplayWidth;
+ final int dh = rotated ? dc.mBaseDisplayWidth : dc.mBaseDisplayHeight;
+ DisplayPolicy.DecorInsets.Info decorInsets = dc.getDisplayPolicy()
+ .getDecorInsetsInfo(rotation, dw, dh);
+ final Rect stableBounds = decorInsets.mOverrideConfigFrame;
+ mTmpOverrideConfigOrientation = stableBounds.width() > stableBounds.height()
+ ? ORIENTATION_LANDSCAPE : ORIENTATION_PORTRAIT;
+ insets = Insets.of(decorInsets.mOverrideNonDecorInsets);
+ } else {
+ insets = Insets.NONE;
+ }
+ mTmpParentAppBoundsOverride.inset(insets);
+ }
+
+ void resetTmpOverrides() {
+ mTmpOverrideDisplayInfo = null;
+ mTmpCompatInsets = null;
+ mTmpParentAppBoundsOverride = null;
+ mTmpOverrideConfigOrientation = ORIENTATION_UNDEFINED;
+ }
}
void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
@@ -2311,7 +2363,9 @@
if (!customContainerPolicy && windowingMode != WINDOWING_MODE_FREEFORM) {
final Rect containingAppBounds;
if (insideParentBounds) {
- containingAppBounds = parentConfig.windowConfiguration.getAppBounds();
+ containingAppBounds = useOverrideInsetsForConfig
+ ? overrideHint.mTmpParentAppBoundsOverride
+ : parentConfig.windowConfiguration.getAppBounds();
} else {
// Restrict appBounds to display non-decor rather than parent because the
// override bounds are beyond the parent. Otherwise, it won't match the
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index 4aa3e36..63ca469 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -1048,7 +1048,7 @@
// the animation played. This puts the layers back into the correct order.
for (int i = displays.size() - 1; i >= 0; --i) {
if (displays.valueAt(i) == null) continue;
- updateDisplayLayers(displays.valueAt(i), t);
+ assignLayers(displays.valueAt(i), t);
}
for (int i = 0; i < info.getRootCount(); ++i) {
@@ -1056,12 +1056,13 @@
}
}
- private static void updateDisplayLayers(DisplayContent dc, SurfaceControl.Transaction t) {
- dc.mTransitionController.mBuildingFinishLayers = true;
+ /** Assigns the layers for the start or end state of transition. */
+ static void assignLayers(WindowContainer<?> wc, SurfaceControl.Transaction t) {
+ wc.mTransitionController.mBuildingFinishLayers = true;
try {
- dc.assignChildLayers(t);
+ wc.assignChildLayers(t);
} finally {
- dc.mTransitionController.mBuildingFinishLayers = false;
+ wc.mTransitionController.mBuildingFinishLayers = false;
}
}
@@ -2717,7 +2718,7 @@
rootLeash.setUnreleasedWarningCallSite("Transition.calculateTransitionRoots");
// Update layers to start transaction because we prevent assignment during collect, so
// the layer of transition root can be correct.
- updateDisplayLayers(dc, startT);
+ assignLayers(dc, startT);
startT.setLayer(rootLeash, leashReference.getLastLayer());
outInfo.addRootLeash(endDisplayId, rootLeash,
ancestor.getBounds().left, ancestor.getBounds().top);
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 8a6c73a..b814ccd 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -3502,10 +3502,11 @@
if (!checkCallingPermission(permission.CONTROL_KEYGUARD, "dismissKeyguard")) {
throw new SecurityException("Requires CONTROL_KEYGUARD permission");
}
- if (!dreamHandlesConfirmKeys() && mAtmService.mKeyguardController.isShowingDream()) {
- mAtmService.mTaskSupervisor.wakeUp("leaveDream");
- }
synchronized (mGlobalLock) {
+ if (!dreamHandlesConfirmKeys()
+ && getDefaultDisplayContentLocked().getDisplayPolicy().isShowingDreamLw()) {
+ mAtmService.mTaskSupervisor.wakeUp("leaveDream");
+ }
mPolicy.dismissKeyguardLw(callback, message);
}
}
diff --git a/services/core/jni/com_android_server_vibrator_VibratorController.cpp b/services/core/jni/com_android_server_vibrator_VibratorController.cpp
index f47a59d..4be21d8 100644
--- a/services/core/jni/com_android_server_vibrator_VibratorController.cpp
+++ b/services/core/jni/com_android_server_vibrator_VibratorController.cpp
@@ -131,17 +131,28 @@
}
std::function<void()> createCallback(jlong vibrationId) {
- return [vibrationId, this]() {
+ auto callbackId = ++mCallbackId;
+ return [vibrationId, callbackId, this]() {
+ auto currentCallbackId = mCallbackId.load();
+ if (currentCallbackId != callbackId) {
+ // This callback is from an older HAL call that is no longer relevant to the service
+ return;
+ }
auto jniEnv = GetOrAttachJNIEnvironment(sJvm);
jniEnv->CallVoidMethod(mCallbackListener, sMethodIdOnComplete, mVibratorId,
vibrationId);
};
}
+ void disableOldCallbacks() {
+ mCallbackId++;
+ }
+
private:
const std::shared_ptr<vibrator::HalController> mHal;
const int32_t mVibratorId;
const jobject mCallbackListener;
+ std::atomic<int64_t> mCallbackId;
};
static aidl::BrakingPwle brakingPwle(aidl::Braking braking, int32_t duration) {
@@ -236,6 +247,7 @@
}
auto offFn = [](vibrator::HalWrapper* hal) { return hal->off(); };
wrapper->halCall<void>(offFn, "off");
+ wrapper->disableOldCallbacks();
}
static void vibratorSetAmplitude(JNIEnv* env, jclass /* clazz */, jlong ptr, jfloat amplitude) {
diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/AndroidTest.xml b/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/AndroidTest.xml
index 820628c..8e6954b 100644
--- a/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/AndroidTest.xml
+++ b/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/AndroidTest.xml
@@ -25,6 +25,12 @@
<option name="test-file-name" value="FrameworksImeTests.apk" />
</target_preparer>
+ <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+ <option name="run-command" value="input keyevent KEYCODE_WAKEUP" />
+ <option name="run-command" value="wm dismiss-keyguard" />
+ <option name="run-command" value="settings put secure immersive_mode_confirmations confirmed" />
+ </target_preparer>
+
<option name="test-tag" value="FrameworksImeTests" />
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java b/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java
index 1535298..2029b71 100644
--- a/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java
+++ b/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java
@@ -48,6 +48,7 @@
import com.android.apps.inputmethod.simpleime.ims.InputMethodServiceWrapper;
import com.android.apps.inputmethod.simpleime.testing.TestActivity;
+import com.android.compatibility.common.util.SystemUtil;
import com.android.internal.inputmethod.InputMethodNavButtonFlags;
import org.junit.After;
@@ -834,8 +835,7 @@
private String executeShellCommand(String cmd) throws IOException {
Log.i(TAG, "Run command: " + cmd);
- return UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
- .executeShellCommand(cmd);
+ return SystemUtil.runShellCommandOrThrow(cmd);
}
private void clickOnEditorText() {
diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/DefaultImeVisibilityApplierTest.java b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/DefaultImeVisibilityApplierTest.java
index 221a991..a4ca317 100644
--- a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/DefaultImeVisibilityApplierTest.java
+++ b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/DefaultImeVisibilityApplierTest.java
@@ -68,12 +68,15 @@
public class DefaultImeVisibilityApplierTest extends InputMethodManagerServiceTestBase {
private DefaultImeVisibilityApplier mVisibilityApplier;
+ private int mUserId = 0;
+
@Before
public void setUp() throws RemoteException {
super.setUp();
mVisibilityApplier =
(DefaultImeVisibilityApplier) mInputMethodManagerService.getVisibilityApplier();
synchronized (ImfLock.class) {
+ mUserId = mInputMethodManagerService.getCurrentImeUserIdLocked();
mInputMethodManagerService.setAttachedClientForTesting(requireNonNull(
mInputMethodManagerService.getClientStateLocked(mMockInputMethodClient)));
}
@@ -103,7 +106,7 @@
assertThrows(IllegalArgumentException.class, () -> {
synchronized (ImfLock.class) {
mVisibilityApplier.applyImeVisibility(mWindowToken, ImeTracker.Token.empty(),
- STATE_INVALID);
+ STATE_INVALID, mUserId);
}
});
}
@@ -112,7 +115,8 @@
public void testApplyImeVisibility_showIme() {
final var statsToken = ImeTracker.Token.empty();
synchronized (ImfLock.class) {
- mVisibilityApplier.applyImeVisibility(mWindowToken, statsToken, STATE_SHOW_IME);
+ mVisibilityApplier.applyImeVisibility(mWindowToken, statsToken, STATE_SHOW_IME,
+ mUserId);
}
verify(mMockWindowManagerInternal).showImePostLayout(eq(mWindowToken), eq(statsToken));
}
@@ -121,7 +125,8 @@
public void testApplyImeVisibility_hideIme() {
final var statsToken = ImeTracker.Token.empty();
synchronized (ImfLock.class) {
- mVisibilityApplier.applyImeVisibility(mWindowToken, statsToken, STATE_HIDE_IME);
+ mVisibilityApplier.applyImeVisibility(mWindowToken, statsToken, STATE_HIDE_IME,
+ mUserId);
}
verify(mMockWindowManagerInternal).hideIme(eq(mWindowToken), anyInt() /* displayId */,
eq(statsToken));
@@ -132,7 +137,7 @@
mInputMethodManagerService.mImeWindowVis = IME_ACTIVE;
synchronized (ImfLock.class) {
mVisibilityApplier.applyImeVisibility(mWindowToken, ImeTracker.Token.empty(),
- STATE_HIDE_IME_EXPLICIT);
+ STATE_HIDE_IME_EXPLICIT, mUserId);
}
verifyHideSoftInput(true, true);
}
@@ -142,7 +147,7 @@
mInputMethodManagerService.mImeWindowVis = IME_ACTIVE;
synchronized (ImfLock.class) {
mVisibilityApplier.applyImeVisibility(mWindowToken, ImeTracker.Token.empty(),
- STATE_HIDE_IME_NOT_ALWAYS);
+ STATE_HIDE_IME_NOT_ALWAYS, mUserId);
}
verifyHideSoftInput(true, true);
}
@@ -151,7 +156,7 @@
public void testApplyImeVisibility_showImeImplicit() throws Exception {
synchronized (ImfLock.class) {
mVisibilityApplier.applyImeVisibility(mWindowToken, ImeTracker.Token.empty(),
- STATE_SHOW_IME_IMPLICIT);
+ STATE_SHOW_IME_IMPLICIT, mUserId);
}
verifyShowSoftInput(true, true, 0 /* showFlags */);
}
@@ -166,10 +171,13 @@
final var statsToken = ImeTracker.Token.empty();
synchronized (ImfLock.class) {
- final int displayIdToShowIme = mInputMethodManagerService.getDisplayIdToShowImeLocked();
+ final var bindingController =
+ mInputMethodManagerService.getInputMethodBindingController(mUserId);
+ final int displayIdToShowIme = bindingController.getDisplayIdToShowIme();
// Verify hideIme will apply the expected displayId when the default IME
// visibility applier app STATE_HIDE_IME.
- mVisibilityApplier.applyImeVisibility(mWindowToken, statsToken, STATE_HIDE_IME);
+ mVisibilityApplier.applyImeVisibility(mWindowToken, statsToken, STATE_HIDE_IME,
+ mUserId);
verify(mInputMethodManagerService.mWindowManagerInternal).hideIme(
eq(mWindowToken), eq(displayIdToShowIme), eq(statsToken));
}
@@ -204,7 +212,9 @@
// Simulate the system hides the IME when switching IME services in different users.
// (e.g. unbinding the IME from the current user to the profile user)
final var statsToken = ImeTracker.Token.empty();
- final int displayIdToShowIme = mInputMethodManagerService.getDisplayIdToShowImeLocked();
+ final var bindingController =
+ mInputMethodManagerService.getInputMethodBindingController(mUserId);
+ final int displayIdToShowIme = bindingController.getDisplayIdToShowIme();
mInputMethodManagerService.hideCurrentInputLocked(mWindowToken,
statsToken, 0 /* flags */, null /* resultReceiver */,
HIDE_SWITCH_USER);
@@ -214,7 +224,7 @@
// the IME hidden state.
// The unbind will cancel the previous stats token, and create a new one internally.
verify(mVisibilityApplier).applyImeVisibility(
- eq(mWindowToken), any(), eq(STATE_HIDE_IME));
+ eq(mWindowToken), any(), eq(STATE_HIDE_IME), eq(mUserId) /* userId */);
verify(mInputMethodManagerService.mWindowManagerInternal).hideIme(
eq(mWindowToken), eq(displayIdToShowIme), and(not(eq(statsToken)), notNull()));
}
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceInfoTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceInfoTest.java
new file mode 100644
index 0000000..bacbf89
--- /dev/null
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceInfoTest.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display;
+
+import static com.android.server.display.DisplayDeviceInfo.DIFF_COLOR_MODE;
+import static com.android.server.display.DisplayDeviceInfo.DIFF_COMMITTED_STATE;
+import static com.android.server.display.DisplayDeviceInfo.DIFF_HDR_SDR_RATIO;
+import static com.android.server.display.DisplayDeviceInfo.DIFF_MODE_ID;
+import static com.android.server.display.DisplayDeviceInfo.DIFF_RENDER_TIMINGS;
+import static com.android.server.display.DisplayDeviceInfo.DIFF_ROTATION;
+import static com.android.server.display.DisplayDeviceInfo.DIFF_STATE;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.view.Display;
+import android.view.Surface;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class DisplayDeviceInfoTest {
+
+ @Test
+ public void testDiff_noChange() {
+ var oldDdi = createInfo();
+ var newDdi = createInfo();
+
+ assertThat(oldDdi.diff(newDdi)).isEqualTo(0);
+ }
+
+ @Test
+ public void testDiff_state() {
+ var oldDdi = createInfo();
+ var newDdi = createInfo();
+
+ newDdi.state = Display.STATE_VR;
+ assertThat(oldDdi.diff(newDdi)).isEqualTo(DIFF_STATE);
+ }
+
+ @Test
+ public void testDiff_committedState() {
+ var oldDdi = createInfo();
+ var newDdi = createInfo();
+
+ newDdi.committedState = Display.STATE_UNKNOWN;
+ assertThat(oldDdi.diff(newDdi)).isEqualTo(DIFF_COMMITTED_STATE);
+ }
+
+ @Test
+ public void testDiff_colorMode() {
+ var oldDdi = createInfo();
+ var newDdi = createInfo();
+
+ newDdi.colorMode = Display.COLOR_MODE_DISPLAY_P3;
+ assertThat(oldDdi.diff(newDdi)).isEqualTo(DIFF_COLOR_MODE);
+ }
+
+ @Test
+ public void testDiff_hdrSdrRatio() {
+ var oldDdi = createInfo();
+ var newDdi = createInfo();
+
+ /* First change new ratio to non-NaN */
+ newDdi.hdrSdrRatio = 2.3f;
+ assertThat(oldDdi.diff(newDdi)).isEqualTo(DIFF_HDR_SDR_RATIO);
+
+ /* Then change old to be non-NaN and also distinct */
+ oldDdi.hdrSdrRatio = 1.1f;
+ assertThat(oldDdi.diff(newDdi)).isEqualTo(DIFF_HDR_SDR_RATIO);
+
+ /* Now make the new one NaN and the old one non-NaN */
+ newDdi.hdrSdrRatio = Float.NaN;
+ assertThat(oldDdi.diff(newDdi)).isEqualTo(DIFF_HDR_SDR_RATIO);
+ }
+
+ @Test
+ public void testDiff_rotation() {
+ var oldDdi = createInfo();
+ var newDdi = createInfo();
+
+ newDdi.rotation = Surface.ROTATION_270;
+ assertThat(oldDdi.diff(newDdi)).isEqualTo(DIFF_ROTATION);
+ }
+
+ @Test
+ public void testDiff_frameRate() {
+ var oldDdi = createInfo();
+ var newDdi = createInfo();
+
+ newDdi.renderFrameRate = 123.4f;
+ assertThat(oldDdi.diff(newDdi)).isEqualTo(DIFF_RENDER_TIMINGS);
+ newDdi.renderFrameRate = oldDdi.renderFrameRate;
+
+ newDdi.appVsyncOffsetNanos = 31222221;
+ assertThat(oldDdi.diff(newDdi)).isEqualTo(DIFF_RENDER_TIMINGS);
+ newDdi.appVsyncOffsetNanos = oldDdi.appVsyncOffsetNanos;
+
+ newDdi.presentationDeadlineNanos = 23000000;
+ assertThat(oldDdi.diff(newDdi)).isEqualTo(DIFF_RENDER_TIMINGS);
+ }
+
+ @Test
+ public void testDiff_modeId() {
+ var oldDdi = createInfo();
+ var newDdi = createInfo();
+
+ newDdi.modeId = 9;
+ assertThat(oldDdi.diff(newDdi)).isEqualTo(DIFF_MODE_ID);
+ }
+
+ private static DisplayDeviceInfo createInfo() {
+ var ddi = new DisplayDeviceInfo();
+ ddi.name = "TestDisplayDeviceInfo";
+ ddi.uniqueId = "test:51651561321";
+ ddi.width = 671;
+ ddi.height = 483;
+ ddi.modeId = 2;
+ ddi.renderFrameRate = 68.9f;
+ ddi.supportedModes = new Display.Mode[] {
+ new Display.Mode.Builder().setRefreshRate(68.9f).setResolution(671, 483).build(),
+ };
+ ddi.appVsyncOffsetNanos = 6233332;
+ ddi.presentationDeadlineNanos = 11500000;
+ ddi.rotation = Surface.ROTATION_90;
+ ddi.state = Display.STATE_ON;
+ ddi.committedState = Display.STATE_DOZE_SUSPEND;
+ return ddi;
+ }
+}
diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategyTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategyTest.java
index 8a33f34..1d04baa 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategyTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategyTest.java
@@ -570,6 +570,86 @@
assertEquals(expectedDisplayBrightnessState, actualDisplayBrightnessState);
}
+ @Test
+ public void
+ updateBrightness_constructsDisplayBrightnessState_withNoAdjustmentFlag_isSlowChange() {
+ BrightnessEvent brightnessEvent = new BrightnessEvent(DISPLAY_ID);
+ mAutomaticBrightnessStrategy = new AutomaticBrightnessStrategy(
+ mContext, DISPLAY_ID, displayId -> brightnessEvent, mDisplayManagerFlags);
+ mAutomaticBrightnessStrategy.setAutomaticBrightnessController(
+ mAutomaticBrightnessController);
+ float brightness = 0.4f;
+ BrightnessReason brightnessReason = new BrightnessReason();
+ brightnessReason.setReason(BrightnessReason.REASON_AUTOMATIC);
+ when(mAutomaticBrightnessController.getAutomaticScreenBrightness(brightnessEvent))
+ .thenReturn(brightness);
+
+ // Set the state such that auto-brightness was already applied
+ mAutomaticBrightnessStrategy.setAutoBrightnessApplied(true);
+
+ // Update the auto-brightess validity state to change the isSlowChange flag
+ mAutomaticBrightnessStrategy.isAutoBrightnessValid();
+
+ DisplayManagerInternal.DisplayPowerRequest displayPowerRequest =
+ mock(DisplayManagerInternal.DisplayPowerRequest.class);
+
+ DisplayBrightnessState expectedDisplayBrightnessState = new DisplayBrightnessState.Builder()
+ .setBrightness(brightness)
+ .setSdrBrightness(brightness)
+ .setBrightnessReason(brightnessReason)
+ .setDisplayBrightnessStrategyName(mAutomaticBrightnessStrategy.getName())
+ .setIsSlowChange(true)
+ .setBrightnessEvent(brightnessEvent)
+ .setBrightnessAdjustmentFlag(0)
+ .setShouldUpdateScreenBrightnessSetting(true)
+ .setIsUserInitiatedChange(true)
+ .build();
+ DisplayBrightnessState actualDisplayBrightnessState = mAutomaticBrightnessStrategy
+ .updateBrightness(new StrategyExecutionRequest(displayPowerRequest, 0.6f,
+ /* userSetBrightnessChanged= */ true));
+ assertEquals(expectedDisplayBrightnessState, actualDisplayBrightnessState);
+ }
+
+
+ @Test
+ public void updateBrightness_autoBrightnessNotApplied_noAdjustments_isNotSlowChange() {
+ BrightnessEvent brightnessEvent = new BrightnessEvent(DISPLAY_ID);
+ mAutomaticBrightnessStrategy = new AutomaticBrightnessStrategy(
+ mContext, DISPLAY_ID, displayId -> brightnessEvent, mDisplayManagerFlags);
+ mAutomaticBrightnessStrategy.setAutomaticBrightnessController(
+ mAutomaticBrightnessController);
+ float brightness = 0.4f;
+ BrightnessReason brightnessReason = new BrightnessReason();
+ brightnessReason.setReason(BrightnessReason.REASON_AUTOMATIC);
+ when(mAutomaticBrightnessController.getAutomaticScreenBrightness(brightnessEvent))
+ .thenReturn(brightness);
+
+ // Set the state such that auto-brightness was not already applied
+ mAutomaticBrightnessStrategy.setAutoBrightnessApplied(false);
+
+ // Update the auto-brightess validity state to change the isSlowChange flag
+ mAutomaticBrightnessStrategy.isAutoBrightnessValid();
+
+ DisplayManagerInternal.DisplayPowerRequest displayPowerRequest =
+ mock(DisplayManagerInternal.DisplayPowerRequest.class);
+
+ DisplayBrightnessState expectedDisplayBrightnessState = new DisplayBrightnessState.Builder()
+ .setBrightness(brightness)
+ .setSdrBrightness(brightness)
+ .setBrightnessReason(brightnessReason)
+ .setDisplayBrightnessStrategyName(mAutomaticBrightnessStrategy.getName())
+ .setIsSlowChange(false)
+ .setBrightnessEvent(brightnessEvent)
+ .setBrightnessAdjustmentFlag(0)
+ .setShouldUpdateScreenBrightnessSetting(true)
+ .setIsUserInitiatedChange(true)
+ .build();
+ DisplayBrightnessState actualDisplayBrightnessState = mAutomaticBrightnessStrategy
+ .updateBrightness(new StrategyExecutionRequest(displayPowerRequest, 0.6f,
+ /* userSetBrightnessChanged= */ true));
+ assertEquals(expectedDisplayBrightnessState, actualDisplayBrightnessState);
+ }
+
private void setPendingAutoBrightnessAdjustment(float pendingAutoBrightnessAdjustment) {
Settings.System.putFloat(mContext.getContentResolver(),
Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ, pendingAutoBrightnessAdjustment);
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/ApplicationStartInfoTest.java b/services/tests/mockingservicestests/src/com/android/server/am/ApplicationStartInfoTest.java
index e88e28b..ee96c2a 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/ApplicationStartInfoTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/ApplicationStartInfoTest.java
@@ -74,6 +74,15 @@
private static final String TAG = ApplicationStartInfoTest.class.getSimpleName();
private static final ComponentName COMPONENT = new ComponentName("com.android.test", ".Foo");
+ private static final int APP_1_UID = 10123;
+ private static final int APP_1_PID_1 = 12345;
+ private static final int APP_1_PID_2 = 12346;
+ private static final int APP_1_DEFINING_UID = 23456;
+ private static final int APP_1_UID_USER_2 = 1010123;
+ private static final int APP_1_PID_USER_2 = 12347;
+ private static final String APP_1_PROCESS_NAME = "com.android.test.stub1:process";
+ private static final String APP_1_PACKAGE_NAME = "com.android.test.stub1";
+
@Rule public ServiceThreadRule mServiceThreadRule = new ServiceThreadRule();
@Mock private AppOpsService mAppOpsService;
@Mock private PackageManagerInternal mPackageManagerInt;
@@ -111,6 +120,12 @@
// Remove stale instance of PackageManagerInternal if there is any
LocalServices.removeServiceForTest(PackageManagerInternal.class);
LocalServices.addService(PackageManagerInternal.class, mPackageManagerInt);
+
+ mAppStartInfoTracker.clearProcessStartInfo(true);
+ mAppStartInfoTracker.mAppStartInfoLoaded.set(true);
+ mAppStartInfoTracker.mAppStartInfoHistoryListSize =
+ mAppStartInfoTracker.APP_START_INFO_HISTORY_LIST_SIZE;
+ doNothing().when(mAppStartInfoTracker).schedulePersistProcessStartInfo(anyBoolean());
}
@After
@@ -120,26 +135,12 @@
@Test
public void testApplicationStartInfo() throws Exception {
- mAppStartInfoTracker.clearProcessStartInfo(true);
- mAppStartInfoTracker.mAppStartInfoLoaded.set(true);
- mAppStartInfoTracker.mAppStartInfoHistoryListSize =
- mAppStartInfoTracker.APP_START_INFO_HISTORY_LIST_SIZE;
mAppStartInfoTracker.mProcStartStoreDir = new File(mContext.getFilesDir(),
AppStartInfoTracker.APP_START_STORE_DIR);
assertTrue(FileUtils.createDir(mAppStartInfoTracker.mProcStartStoreDir));
mAppStartInfoTracker.mProcStartInfoFile = new File(mAppStartInfoTracker.mProcStartStoreDir,
AppStartInfoTracker.APP_START_INFO_FILE);
- doNothing().when(mAppStartInfoTracker).schedulePersistProcessStartInfo(anyBoolean());
-
- final int app1Uid = 10123;
- final int app1Pid1 = 12345;
- final int app1Pid2 = 12346;
- final int app1DefiningUid = 23456;
- final int app1UidUser2 = 1010123;
- final int app1PidUser2 = 12347;
- final String app1ProcessName = "com.android.test.stub1:process";
- final String app1PackageName = "com.android.test.stub1";
final long appStartTimestampIntentStarted = 1000000;
final long appStartTimestampActivityLaunchFinished = 2000000;
final long appStartTimestampFirstFrameDrawn = 2500000;
@@ -149,23 +150,23 @@
final long appStartTimestampRContentProvider = 6000000;
ProcessRecord app = makeProcessRecord(
- app1Pid1, // pid
- app1Uid, // uid
- app1Uid, // packageUid
+ APP_1_PID_1, // pid
+ APP_1_UID, // uid
+ APP_1_UID, // packageUid
null, // definingUid
- app1ProcessName, // processName
- app1PackageName); // packageName
+ APP_1_PROCESS_NAME, // processName
+ APP_1_PACKAGE_NAME); // packageName
ArrayList<ApplicationStartInfo> list = new ArrayList<ApplicationStartInfo>();
// Case 1: Activity start intent failed
mAppStartInfoTracker.onIntentStarted(buildIntent(COMPONENT),
appStartTimestampIntentStarted);
- mAppStartInfoTracker.getStartInfo(app1PackageName, app1Uid, app1Pid1, 0, list);
+ mAppStartInfoTracker.getStartInfo(APP_1_PACKAGE_NAME, APP_1_UID, APP_1_PID_1, 0, list);
verifyInProgressRecordsSize(1);
assertEquals(list.size(), 0);
- verifyInProgApplicationStartInfo(
+ verifyInProgressApplicationStartInfo(
0, // index
0, // pid
0, // uid
@@ -179,7 +180,7 @@
mAppStartInfoTracker.onIntentFailed(appStartTimestampIntentStarted);
list.clear();
- mAppStartInfoTracker.getStartInfo(app1PackageName, app1Uid, app1Pid1, 0, list);
+ mAppStartInfoTracker.getStartInfo(APP_1_PACKAGE_NAME, APP_1_UID, APP_1_PID_1, 0, list);
verifyInProgressRecordsSize(0);
assertEquals(list.size(), 0);
@@ -189,24 +190,24 @@
mAppStartInfoTracker.onIntentStarted(buildIntent(COMPONENT),
appStartTimestampIntentStarted);
list.clear();
- mAppStartInfoTracker.getStartInfo(app1PackageName, app1Uid, app1Pid1, 0, list);
+ mAppStartInfoTracker.getStartInfo(APP_1_PACKAGE_NAME, APP_1_UID, APP_1_PID_1, 0, list);
verifyInProgressRecordsSize(1);
assertEquals(list.size(), 0);
mAppStartInfoTracker.onActivityLaunched(appStartTimestampIntentStarted, COMPONENT,
ApplicationStartInfo.START_TYPE_COLD, app);
list.clear();
- mAppStartInfoTracker.getStartInfo(app1PackageName, app1Uid, app1Pid1, 0, list);
+ mAppStartInfoTracker.getStartInfo(APP_1_PACKAGE_NAME, APP_1_UID, APP_1_PID_1, 0, list);
verifyInProgressRecordsSize(1);
assertEquals(list.size(), 1);
- verifyInProgApplicationStartInfo(
+ verifyInProgressApplicationStartInfo(
0, // index
- app1Pid1, // pid
- app1Uid, // uid
- app1Uid, // packageUid
+ APP_1_PID_1, // pid
+ APP_1_UID, // uid
+ APP_1_UID, // packageUid
null, // definingUid
- app1ProcessName, // processName
+ APP_1_PROCESS_NAME, // processName
ApplicationStartInfo.START_REASON_START_ACTIVITY, // reason
ApplicationStartInfo.STARTUP_STATE_STARTED, // startup state
ApplicationStartInfo.START_TYPE_COLD, // state type
@@ -214,17 +215,17 @@
mAppStartInfoTracker.onActivityLaunchCancelled(appStartTimestampIntentStarted);
list.clear();
- mAppStartInfoTracker.getStartInfo(app1PackageName, app1Uid, app1Pid1, 0, list);
+ mAppStartInfoTracker.getStartInfo(APP_1_PACKAGE_NAME, APP_1_UID, APP_1_PID_1, 0, list);
verifyInProgressRecordsSize(0);
assertEquals(list.size(), 1);
verifyApplicationStartInfo(
list.get(0), // info
- app1Pid1, // pid
- app1Uid, // uid
- app1Uid, // packageUid
+ APP_1_PID_1, // pid
+ APP_1_UID, // uid
+ APP_1_UID, // packageUid
null, // definingUid
- app1ProcessName, // processName
+ APP_1_PROCESS_NAME, // processName
ApplicationStartInfo.START_REASON_START_ACTIVITY, // reason
ApplicationStartInfo.STARTUP_STATE_ERROR, // startup state
ApplicationStartInfo.START_TYPE_COLD, // state type
@@ -236,24 +237,24 @@
mAppStartInfoTracker.onIntentStarted(buildIntent(COMPONENT),
appStartTimestampIntentStarted);
list.clear();
- mAppStartInfoTracker.getStartInfo(app1PackageName, app1Uid, app1Pid1, 0, list);
+ mAppStartInfoTracker.getStartInfo(APP_1_PACKAGE_NAME, APP_1_UID, APP_1_PID_1, 0, list);
verifyInProgressRecordsSize(1);
assertEquals(list.size(), 0);
mAppStartInfoTracker.onActivityLaunched(appStartTimestampIntentStarted, COMPONENT,
ApplicationStartInfo.START_TYPE_COLD, app);
list.clear();
- mAppStartInfoTracker.getStartInfo(app1PackageName, app1Uid, app1Pid1, 0, list);
+ mAppStartInfoTracker.getStartInfo(APP_1_PACKAGE_NAME, APP_1_UID, APP_1_PID_1, 0, list);
verifyInProgressRecordsSize(1);
assertEquals(list.size(), 1);
- verifyInProgApplicationStartInfo(
+ verifyInProgressApplicationStartInfo(
0, // index
- app1Pid1, // pid
- app1Uid, // uid
- app1Uid, // packageUid
+ APP_1_PID_1, // pid
+ APP_1_UID, // uid
+ APP_1_UID, // packageUid
null, // definingUid
- app1ProcessName, // processName
+ APP_1_PROCESS_NAME, // processName
ApplicationStartInfo.START_REASON_START_ACTIVITY, // reason
ApplicationStartInfo.STARTUP_STATE_STARTED, // startup state
ApplicationStartInfo.START_TYPE_COLD, // state type
@@ -261,11 +262,11 @@
verifyApplicationStartInfo(
list.get(0), // info
- app1Pid1, // pid
- app1Uid, // uid
- app1Uid, // packageUid
+ APP_1_PID_1, // pid
+ APP_1_UID, // uid
+ APP_1_UID, // packageUid
null, // definingUid
- app1ProcessName, // processName
+ APP_1_PROCESS_NAME, // processName
ApplicationStartInfo.START_REASON_START_ACTIVITY, // reason
ApplicationStartInfo.STARTUP_STATE_STARTED, // startup state
ApplicationStartInfo.START_TYPE_COLD, // state type
@@ -273,20 +274,20 @@
mAppStartInfoTracker.onActivityLaunchFinished(appStartTimestampIntentStarted, COMPONENT,
appStartTimestampActivityLaunchFinished, ApplicationStartInfo.LAUNCH_MODE_STANDARD);
- mAppStartInfoTracker.addTimestampToStart(app1PackageName, app1Uid,
+ mAppStartInfoTracker.addTimestampToStart(APP_1_PACKAGE_NAME, APP_1_UID,
appStartTimestampFirstFrameDrawn, ApplicationStartInfo.START_TIMESTAMP_FIRST_FRAME);
list.clear();
- mAppStartInfoTracker.getStartInfo(app1PackageName, app1Uid, app1Pid1, 0, list);
+ mAppStartInfoTracker.getStartInfo(APP_1_PACKAGE_NAME, APP_1_UID, APP_1_PID_1, 0, list);
verifyInProgressRecordsSize(1);
assertEquals(list.size(), 1);
- verifyInProgApplicationStartInfo(
+ verifyInProgressApplicationStartInfo(
0, // index
- app1Pid1, // pid
- app1Uid, // uid
- app1Uid, // packageUid
+ APP_1_PID_1, // pid
+ APP_1_UID, // uid
+ APP_1_UID, // packageUid
null, // definingUid
- app1ProcessName, // processName
+ APP_1_PROCESS_NAME, // processName
ApplicationStartInfo.START_REASON_START_ACTIVITY, // reason
ApplicationStartInfo.STARTUP_STATE_FIRST_FRAME_DRAWN, // startup state
ApplicationStartInfo.START_TYPE_COLD, // state type
@@ -295,17 +296,17 @@
mAppStartInfoTracker.onReportFullyDrawn(appStartTimestampIntentStarted,
appStartTimestampReportFullyDrawn);
list.clear();
- mAppStartInfoTracker.getStartInfo(app1PackageName, app1Uid, app1Pid1, 0, list);
+ mAppStartInfoTracker.getStartInfo(APP_1_PACKAGE_NAME, APP_1_UID, APP_1_PID_1, 0, list);
verifyInProgressRecordsSize(0);
assertEquals(list.size(), 1);
verifyApplicationStartInfo(
list.get(0), // info
- app1Pid1, // pid
- app1Uid, // uid
- app1Uid, // packageUid
+ APP_1_PID_1, // pid
+ APP_1_UID, // uid
+ APP_1_UID, // packageUid
null, // definingUid
- app1ProcessName, // processName
+ APP_1_PROCESS_NAME, // processName
ApplicationStartInfo.START_REASON_START_ACTIVITY, // reason
ApplicationStartInfo.STARTUP_STATE_FIRST_FRAME_DRAWN, // startup state
ApplicationStartInfo.START_TYPE_COLD, // state type
@@ -316,26 +317,26 @@
// Case 4: Create an other app1 record with different pid started for a service
sleep(1);
app = makeProcessRecord(
- app1Pid2, // pid
- app1Uid, // uid
- app1Uid, // packageUid
- app1DefiningUid, // definingUid
- app1ProcessName, // processName
- app1PackageName); // packageName
+ APP_1_PID_2, // pid
+ APP_1_UID, // uid
+ APP_1_UID, // packageUid
+ APP_1_DEFINING_UID, // definingUid
+ APP_1_PROCESS_NAME, // processName
+ APP_1_PACKAGE_NAME); // packageName
ServiceRecord service = ServiceRecord.newEmptyInstanceForTest(mAms);
mAppStartInfoTracker.handleProcessServiceStart(appStartTimestampService, app, service);
list.clear();
- mAppStartInfoTracker.getStartInfo(app1PackageName, app1Uid, 0, 0, list);
+ mAppStartInfoTracker.getStartInfo(APP_1_PACKAGE_NAME, APP_1_UID, 0, 0, list);
assertEquals(list.size(), 2);
verifyApplicationStartInfo(
list.get(0), // info
- app1Pid2, // pid
- app1Uid, // uid
- app1Uid, // packageUid
- app1DefiningUid, // definingUid
- app1ProcessName, // processName
+ APP_1_PID_2, // pid
+ APP_1_UID, // uid
+ APP_1_UID, // packageUid
+ APP_1_DEFINING_UID, // definingUid
+ APP_1_PROCESS_NAME, // processName
ApplicationStartInfo.START_REASON_SERVICE, // reason
ApplicationStartInfo.STARTUP_STATE_STARTED, // startup state
ApplicationStartInfo.START_TYPE_COLD, // state type
@@ -344,39 +345,41 @@
// Case 5: Create an instance of app1 with a different user started for a broadcast
sleep(1);
app = makeProcessRecord(
- app1PidUser2, // pid
- app1UidUser2, // uid
- app1UidUser2, // packageUid
+ APP_1_PID_USER_2, // pid
+ APP_1_UID_USER_2, // uid
+ APP_1_UID_USER_2, // packageUid
null, // definingUid
- app1ProcessName, // processName
- app1PackageName); // packageName
+ APP_1_PROCESS_NAME, // processName
+ APP_1_PACKAGE_NAME); // packageName
mAppStartInfoTracker.handleProcessBroadcastStart(appStartTimestampBroadcast, app,
buildIntent(COMPONENT), false /* isAlarm */);
list.clear();
- mAppStartInfoTracker.getStartInfo(app1PackageName, app1UidUser2, app1PidUser2, 0, list);
+ mAppStartInfoTracker.getStartInfo(APP_1_PACKAGE_NAME, APP_1_UID_USER_2, APP_1_PID_USER_2, 0,
+ list);
assertEquals(list.size(), 1);
verifyApplicationStartInfo(
list.get(0), // info
- app1PidUser2, // pid
- app1UidUser2, // uid
- app1UidUser2, // packageUid
+ APP_1_PID_USER_2, // pid
+ APP_1_UID_USER_2, // uid
+ APP_1_UID_USER_2, // packageUid
null, // definingUid
- app1ProcessName, // processName
+ APP_1_PROCESS_NAME, // processName
ApplicationStartInfo.START_REASON_BROADCAST, // reason
ApplicationStartInfo.STARTUP_STATE_STARTED, // startup state
ApplicationStartInfo.START_TYPE_COLD, // state type
ApplicationStartInfo.LAUNCH_MODE_STANDARD); // launch mode
// Case 6: User 2 gets removed
- mAppStartInfoTracker.onPackageRemoved(app1PackageName, app1UidUser2, false);
+ mAppStartInfoTracker.onPackageRemoved(APP_1_PACKAGE_NAME, APP_1_UID_USER_2, false);
list.clear();
- mAppStartInfoTracker.getStartInfo(app1PackageName, app1UidUser2, app1PidUser2, 0, list);
+ mAppStartInfoTracker.getStartInfo(APP_1_PACKAGE_NAME, APP_1_UID_USER_2, APP_1_PID_USER_2, 0,
+ list);
assertEquals(list.size(), 0);
list.clear();
- mAppStartInfoTracker.getStartInfo(app1PackageName, app1Uid, app1PidUser2, 0, list);
+ mAppStartInfoTracker.getStartInfo(APP_1_PACKAGE_NAME, APP_1_UID, APP_1_PID_USER_2, 0, list);
assertEquals(list.size(), 2);
@@ -416,7 +419,7 @@
// Case 8: Save and load again
ArrayList<ApplicationStartInfo> original = new ArrayList<ApplicationStartInfo>();
- mAppStartInfoTracker.getStartInfo(null, app1Uid, 0, 0, original);
+ mAppStartInfoTracker.getStartInfo(null, APP_1_UID, 0, 0, original);
assertTrue(original.size() > 0);
mAppStartInfoTracker.persistProcessStartInfo();
@@ -424,12 +427,12 @@
mAppStartInfoTracker.clearProcessStartInfo(false);
list.clear();
- mAppStartInfoTracker.getStartInfo(null, app1Uid, 0, 0, list);
+ mAppStartInfoTracker.getStartInfo(null, APP_1_UID, 0, 0, list);
assertEquals(0, list.size());
mAppStartInfoTracker.loadExistingProcessStartInfo();
list.clear();
- mAppStartInfoTracker.getStartInfo(null, app1Uid, 0, 0, list);
+ mAppStartInfoTracker.getStartInfo(null, APP_1_UID, 0, 0, list);
assertEquals(original.size(), list.size());
for (int i = list.size() - 1; i >= 0; i--) {
@@ -437,6 +440,48 @@
}
}
+ /**
+ * Test to make sure that in progress records stay within their size limits and discard the
+ * correct records.
+ */
+ @SuppressWarnings("GuardedBy")
+ @Test
+ public void testInProgressRecordsLimit() throws Exception {
+ ProcessRecord app = makeProcessRecord(
+ APP_1_PID_1, // pid
+ APP_1_UID, // uid
+ APP_1_UID, // packageUid
+ null, // definingUid
+ APP_1_PROCESS_NAME, // processName
+ APP_1_PACKAGE_NAME); // packageName
+
+ // Mock performing 2 x MAX_IN_PROGRESS_RECORDS successful starts and ensure that the list
+ // never exceeds the expected size of MAX_IN_PROGRESS_RECORDS.
+ for (int i = 0; i < AppStartInfoTracker.MAX_IN_PROGRESS_RECORDS * 2; i++) {
+ Long startTime = Long.valueOf(i);
+ mAppStartInfoTracker.onIntentStarted(buildIntent(COMPONENT), startTime);
+ verifyInProgressRecordsSize(
+ Math.min(i + 1, AppStartInfoTracker.MAX_IN_PROGRESS_RECORDS));
+
+ mAppStartInfoTracker.onActivityLaunched(startTime, COMPONENT,
+ ApplicationStartInfo.START_TYPE_COLD, app);
+ verifyInProgressRecordsSize(
+ Math.min(i + 1, AppStartInfoTracker.MAX_IN_PROGRESS_RECORDS));
+
+ mAppStartInfoTracker.onActivityLaunchFinished(startTime, COMPONENT,
+ startTime + 100, ApplicationStartInfo.LAUNCH_MODE_STANDARD);
+ verifyInProgressRecordsSize(
+ Math.min(i + 1, AppStartInfoTracker.MAX_IN_PROGRESS_RECORDS));
+
+ // Make sure that the record added in this iteration is still present.
+ assertTrue(mAppStartInfoTracker.mInProgressRecords.containsKey(startTime));
+ }
+
+ // Confirm that after 2 x MAX_IN_PROGRESS_RECORDS starts only MAX_IN_PROGRESS_RECORDS are
+ // present.
+ verifyInProgressRecordsSize(AppStartInfoTracker.MAX_IN_PROGRESS_RECORDS);
+ }
+
private static <T> void setFieldValue(Class clazz, Object obj, String fieldName, T val) {
try {
Field field = clazz.getDeclaredField(fieldName);
@@ -484,16 +529,16 @@
private void verifyInProgressRecordsSize(int expectedSize) {
synchronized (mAppStartInfoTracker.mLock) {
- assertEquals(mAppStartInfoTracker.mInProgRecords.size(), expectedSize);
+ assertEquals(mAppStartInfoTracker.mInProgressRecords.size(), expectedSize);
}
}
- private void verifyInProgApplicationStartInfo(int index,
+ private void verifyInProgressApplicationStartInfo(int index,
Integer pid, Integer uid, Integer packageUid,
Integer definingUid, String processName,
Integer reason, Integer startupState, Integer startType, Integer launchMode) {
synchronized (mAppStartInfoTracker.mLock) {
- verifyApplicationStartInfo(mAppStartInfoTracker.mInProgRecords.valueAt(index),
+ verifyApplicationStartInfo(mAppStartInfoTracker.mInProgressRecords.valueAt(index),
pid, uid, packageUid, definingUid, processName, reason, startupState,
startType, launchMode);
}
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsTest.java
index 976cc18..a3f0770 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsTest.java
@@ -91,7 +91,7 @@
final Parcel parcel = Parcel.obtain();
parcel.writeParcelable(outBatteryUsageStats, 0);
- assertThat(parcel.dataSize()).isLessThan(10000);
+ assertThat(parcel.dataSize()).isLessThan(12000);
parcel.setDataPosition(0);
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/CameraPowerStatsTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/CameraPowerStatsTest.java
new file mode 100644
index 0000000..36deb08
--- /dev/null
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/CameraPowerStatsTest.java
@@ -0,0 +1,270 @@
+/*
+ * 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.power.stats;
+
+import static android.os.BatteryConsumer.PROCESS_STATE_BACKGROUND;
+import static android.os.BatteryConsumer.PROCESS_STATE_CACHED;
+import static android.os.BatteryConsumer.PROCESS_STATE_FOREGROUND;
+import static android.os.BatteryConsumer.PROCESS_STATE_FOREGROUND_SERVICE;
+
+import static com.android.server.power.stats.AggregatedPowerStatsConfig.POWER_STATE_OTHER;
+import static com.android.server.power.stats.AggregatedPowerStatsConfig.SCREEN_STATE_ON;
+import static com.android.server.power.stats.AggregatedPowerStatsConfig.SCREEN_STATE_OTHER;
+import static com.android.server.power.stats.AggregatedPowerStatsConfig.STATE_POWER;
+import static com.android.server.power.stats.AggregatedPowerStatsConfig.STATE_PROCESS_STATE;
+import static com.android.server.power.stats.AggregatedPowerStatsConfig.STATE_SCREEN;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.when;
+
+import android.hardware.power.stats.EnergyConsumerType;
+import android.os.BatteryConsumer;
+import android.os.BatteryStats;
+import android.os.Handler;
+import android.os.Process;
+import android.platform.test.ravenwood.RavenwoodRule;
+
+import com.android.internal.os.Clock;
+import com.android.internal.os.MonotonicClock;
+import com.android.internal.os.PowerProfile;
+import com.android.internal.os.PowerStats;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.function.IntSupplier;
+
+public class CameraPowerStatsTest {
+ @Rule(order = 0)
+ public final RavenwoodRule mRavenwood = new RavenwoodRule.Builder()
+ .setProvideMainThread(true)
+ .build();
+
+ @Rule(order = 1)
+ public final BatteryUsageStatsRule mStatsRule = new BatteryUsageStatsRule()
+ .setAveragePower(PowerProfile.POWER_CAMERA, 100.0)
+ .initMeasuredEnergyStatsLocked();
+
+ private static final double PRECISION = 0.00001;
+ private static final int APP_UID1 = Process.FIRST_APPLICATION_UID + 42;
+ private static final int APP_UID2 = Process.FIRST_APPLICATION_UID + 101;
+ private static final int VOLTAGE_MV = 3500;
+ private static final int ENERGY_CONSUMER_ID = 777;
+
+ private final PowerStatsUidResolver mUidResolver = new PowerStatsUidResolver();
+ @Mock
+ private PowerStatsCollector.ConsumedEnergyRetriever mConsumedEnergyRetriever;
+
+ EnergyConsumerPowerStatsCollector.Injector mInjector =
+ new EnergyConsumerPowerStatsCollector.Injector() {
+ @Override
+ public Handler getHandler() {
+ return mStatsRule.getHandler();
+ }
+
+ @Override
+ public Clock getClock() {
+ return mStatsRule.getMockClock();
+ }
+
+ @Override
+ public PowerStatsUidResolver getUidResolver() {
+ return mUidResolver;
+ }
+
+ @Override
+ public long getPowerStatsCollectionThrottlePeriod(String powerComponentName) {
+ return 0;
+ }
+
+ @Override
+ public PowerStatsCollector.ConsumedEnergyRetriever getConsumedEnergyRetriever() {
+ return mConsumedEnergyRetriever;
+ }
+
+ @Override
+ public IntSupplier getVoltageSupplier() {
+ return () -> VOLTAGE_MV;
+ }
+ };
+
+ private MonotonicClock mMonotonicClock;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ mMonotonicClock = new MonotonicClock(0, mStatsRule.getMockClock());
+ }
+
+ @Test
+ public void energyConsumerModel() {
+ when(mConsumedEnergyRetriever.getEnergyConsumerIds(EnergyConsumerType.CAMERA, null))
+ .thenReturn(new int[]{ENERGY_CONSUMER_ID});
+ CameraPowerStatsProcessor processor = new CameraPowerStatsProcessor(
+ mStatsRule.getPowerProfile(), mUidResolver);
+
+ PowerComponentAggregatedPowerStats stats = createAggregatedPowerStats(processor);
+
+ CameraPowerStatsCollector collector = new CameraPowerStatsCollector(mInjector);
+ collector.addConsumer(
+ powerStats -> {
+ processor.addPowerStats(stats, powerStats, mMonotonicClock.monotonicTime());
+ });
+ collector.setEnabled(true);
+
+ // Establish a baseline
+ when(mConsumedEnergyRetriever.getConsumedEnergyUws(new int[]{ENERGY_CONSUMER_ID}))
+ .thenReturn(new long[]{uCtoUj(10000)});
+ collector.collectAndDeliverStats();
+
+ processor.noteStateChange(stats, buildHistoryItem(0, true, APP_UID1));
+
+ // Turn the screen off after 2.5 seconds
+ stats.setState(STATE_SCREEN, SCREEN_STATE_OTHER, 2500);
+ stats.setUidState(APP_UID1, STATE_PROCESS_STATE, PROCESS_STATE_BACKGROUND, 2500);
+ stats.setUidState(APP_UID1, STATE_PROCESS_STATE, PROCESS_STATE_FOREGROUND_SERVICE, 5000);
+
+ processor.noteStateChange(stats, buildHistoryItem(6000, false, APP_UID1));
+
+ when(mConsumedEnergyRetriever.getConsumedEnergyUws(new int[]{ENERGY_CONSUMER_ID}))
+ .thenReturn(new long[]{uCtoUj(2_170_000)});
+ collector.collectAndDeliverStats();
+
+ processor.noteStateChange(stats, buildHistoryItem(7000, true, APP_UID2));
+
+ mStatsRule.setTime(11_000, 11_000);
+ when(mConsumedEnergyRetriever.getConsumedEnergyUws(new int[]{ENERGY_CONSUMER_ID}))
+ .thenReturn(new long[]{uCtoUj(3_610_000)});
+ collector.collectAndDeliverStats();
+
+ processor.finish(stats, 11_000);
+
+ PowerStats.Descriptor descriptor = stats.getPowerStatsDescriptor();
+ BinaryStatePowerStatsLayout statsLayout = new BinaryStatePowerStatsLayout();
+ statsLayout.fromExtras(descriptor.extras);
+
+ // Total estimated power = 3,600,000 uC = 1.0 mAh
+ // of which 3,000,000 is distributed:
+ // Screen-on - 2500/6000 * 2160000 = 900000 uC = 0.25 mAh
+ // Screen-off - 3500/6000 * 2160000 = 1260000 uC = 0.35 mAh
+ // and 600,000 was fully with screen off:
+ // Screen-off - 1440000 uC = 0.4 mAh
+ long[] deviceStats = new long[descriptor.statsArrayLength];
+ stats.getDeviceStats(deviceStats, states(POWER_STATE_OTHER, SCREEN_STATE_ON));
+ assertThat(statsLayout.getDevicePowerEstimate(deviceStats))
+ .isWithin(PRECISION).of(0.25);
+
+ stats.getDeviceStats(deviceStats, states(POWER_STATE_OTHER, SCREEN_STATE_OTHER));
+ assertThat(statsLayout.getDevicePowerEstimate(deviceStats))
+ .isWithin(PRECISION).of(0.35 + 0.4);
+
+ // UID1 =
+ // 2,160,000 uC = 0.6 mAh
+ // split between three different states
+ // fg screen-on: 2500/6000
+ // bg screen-off: 2500/6000
+ // fgs screen-off: 1000/6000
+ double expectedPower1 = 0.6;
+ long[] uidStats = new long[descriptor.uidStatsArrayLength];
+ stats.getUidStats(uidStats, APP_UID1,
+ states(POWER_STATE_OTHER, SCREEN_STATE_ON, PROCESS_STATE_FOREGROUND));
+ assertThat(statsLayout.getUidPowerEstimate(uidStats))
+ .isWithin(PRECISION).of(expectedPower1 * 2500 / 6000);
+
+
+ stats.getUidStats(uidStats, APP_UID1,
+ states(POWER_STATE_OTHER, SCREEN_STATE_OTHER, PROCESS_STATE_BACKGROUND));
+ assertThat(statsLayout.getUidPowerEstimate(uidStats))
+ .isWithin(PRECISION).of(expectedPower1 * 2500 / 6000);
+
+ stats.getUidStats(uidStats, APP_UID1,
+ states(POWER_STATE_OTHER, SCREEN_STATE_OTHER, PROCESS_STATE_FOREGROUND_SERVICE));
+ assertThat(statsLayout.getUidPowerEstimate(uidStats))
+ .isWithin(PRECISION).of(expectedPower1 * 1000 / 6000);
+
+ // UID2 =
+ // 1440000 mA-ms = 0.4 mAh
+ // all in the same state
+ double expectedPower2 = 0.4;
+ stats.getUidStats(uidStats, APP_UID2,
+ states(POWER_STATE_OTHER, SCREEN_STATE_OTHER, PROCESS_STATE_CACHED));
+ assertThat(statsLayout.getUidPowerEstimate(uidStats))
+ .isWithin(PRECISION).of(expectedPower2);
+
+ stats.getUidStats(uidStats, APP_UID2,
+ states(POWER_STATE_OTHER, SCREEN_STATE_ON, PROCESS_STATE_CACHED));
+ assertThat(statsLayout.getUidPowerEstimate(uidStats))
+ .isWithin(PRECISION).of(0);
+ }
+
+ private BatteryStats.HistoryItem buildHistoryItem(int timestamp, boolean stateOn,
+ int uid) {
+ mStatsRule.setTime(timestamp, timestamp);
+ BatteryStats.HistoryItem historyItem = new BatteryStats.HistoryItem();
+ historyItem.time = mMonotonicClock.monotonicTime();
+ historyItem.states2 = stateOn ? BatteryStats.HistoryItem.STATE2_CAMERA_FLAG : 0;
+ if (stateOn) {
+ historyItem.eventCode = BatteryStats.HistoryItem.EVENT_STATE_CHANGE
+ | BatteryStats.HistoryItem.EVENT_FLAG_START;
+ } else {
+ historyItem.eventCode = BatteryStats.HistoryItem.EVENT_STATE_CHANGE
+ | BatteryStats.HistoryItem.EVENT_FLAG_FINISH;
+ }
+ historyItem.eventTag = historyItem.localEventTag;
+ historyItem.eventTag.uid = uid;
+ historyItem.eventTag.string = "camera";
+ return historyItem;
+ }
+
+ private int[] states(int... states) {
+ return states;
+ }
+
+ private static PowerComponentAggregatedPowerStats createAggregatedPowerStats(
+ BinaryStatePowerStatsProcessor processor) {
+ AggregatedPowerStatsConfig config = new AggregatedPowerStatsConfig();
+ config.trackPowerComponent(BatteryConsumer.POWER_COMPONENT_CAMERA)
+ .trackDeviceStates(
+ AggregatedPowerStatsConfig.STATE_POWER,
+ AggregatedPowerStatsConfig.STATE_SCREEN)
+ .trackUidStates(
+ AggregatedPowerStatsConfig.STATE_POWER,
+ AggregatedPowerStatsConfig.STATE_SCREEN,
+ AggregatedPowerStatsConfig.STATE_PROCESS_STATE)
+ .setProcessor(processor);
+
+ AggregatedPowerStats aggregatedPowerStats = new AggregatedPowerStats(config);
+ PowerComponentAggregatedPowerStats powerComponentStats =
+ aggregatedPowerStats.getPowerComponentStats(BatteryConsumer.POWER_COMPONENT_CAMERA);
+ processor.start(powerComponentStats, 0);
+
+ powerComponentStats.setState(STATE_POWER, POWER_STATE_OTHER, 0);
+ powerComponentStats.setState(STATE_SCREEN, SCREEN_STATE_ON, 0);
+ powerComponentStats.setUidState(APP_UID1, STATE_PROCESS_STATE, PROCESS_STATE_FOREGROUND, 0);
+ powerComponentStats.setUidState(APP_UID2, STATE_PROCESS_STATE, PROCESS_STATE_CACHED, 0);
+
+ return powerComponentStats;
+ }
+
+ private static long uCtoUj(long uc) {
+ return (long) (uc * (double) VOLTAGE_MV / 1000);
+ }
+}
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/GnssPowerStatsTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/GnssPowerStatsTest.java
new file mode 100644
index 0000000..8a391c6
--- /dev/null
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/GnssPowerStatsTest.java
@@ -0,0 +1,375 @@
+/*
+ * 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.power.stats;
+
+import static android.os.BatteryConsumer.PROCESS_STATE_BACKGROUND;
+import static android.os.BatteryConsumer.PROCESS_STATE_CACHED;
+import static android.os.BatteryConsumer.PROCESS_STATE_FOREGROUND;
+import static android.os.BatteryConsumer.PROCESS_STATE_FOREGROUND_SERVICE;
+
+import static com.android.server.power.stats.AggregatedPowerStatsConfig.POWER_STATE_OTHER;
+import static com.android.server.power.stats.AggregatedPowerStatsConfig.SCREEN_STATE_ON;
+import static com.android.server.power.stats.AggregatedPowerStatsConfig.SCREEN_STATE_OTHER;
+import static com.android.server.power.stats.AggregatedPowerStatsConfig.STATE_POWER;
+import static com.android.server.power.stats.AggregatedPowerStatsConfig.STATE_PROCESS_STATE;
+import static com.android.server.power.stats.AggregatedPowerStatsConfig.STATE_SCREEN;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.when;
+
+import android.hardware.power.stats.EnergyConsumerType;
+import android.location.GnssSignalQuality;
+import android.os.BatteryConsumer;
+import android.os.BatteryStats;
+import android.os.Handler;
+import android.os.Process;
+import android.platform.test.ravenwood.RavenwoodRule;
+
+import com.android.internal.os.Clock;
+import com.android.internal.os.MonotonicClock;
+import com.android.internal.os.PowerProfile;
+import com.android.internal.os.PowerStats;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.function.IntSupplier;
+
+public class GnssPowerStatsTest {
+ @Rule(order = 0)
+ public final RavenwoodRule mRavenwood = new RavenwoodRule.Builder()
+ .setProvideMainThread(true)
+ .build();
+
+ @Rule(order = 1)
+ public final BatteryUsageStatsRule mStatsRule = new BatteryUsageStatsRule()
+ .setAveragePower(PowerProfile.POWER_GPS_ON, 100.0)
+ .setAveragePower(PowerProfile.POWER_GPS_SIGNAL_QUALITY_BASED, new double[]{1000, 100})
+ .initMeasuredEnergyStatsLocked();
+
+ private static final double PRECISION = 0.00001;
+ private static final int APP_UID1 = Process.FIRST_APPLICATION_UID + 42;
+ private static final int APP_UID2 = Process.FIRST_APPLICATION_UID + 101;
+ private static final int VOLTAGE_MV = 3500;
+ private static final int ENERGY_CONSUMER_ID = 777;
+
+ private final PowerStatsUidResolver mUidResolver = new PowerStatsUidResolver();
+ @Mock
+ private PowerStatsCollector.ConsumedEnergyRetriever mConsumedEnergyRetriever;
+
+ EnergyConsumerPowerStatsCollector.Injector mInjector =
+ new EnergyConsumerPowerStatsCollector.Injector() {
+ @Override
+ public Handler getHandler() {
+ return mStatsRule.getHandler();
+ }
+
+ @Override
+ public Clock getClock() {
+ return mStatsRule.getMockClock();
+ }
+
+ @Override
+ public PowerStatsUidResolver getUidResolver() {
+ return mUidResolver;
+ }
+
+ @Override
+ public long getPowerStatsCollectionThrottlePeriod(String powerComponentName) {
+ return 0;
+ }
+
+ @Override
+ public PowerStatsCollector.ConsumedEnergyRetriever getConsumedEnergyRetriever() {
+ return mConsumedEnergyRetriever;
+ }
+
+ @Override
+ public IntSupplier getVoltageSupplier() {
+ return () -> VOLTAGE_MV;
+ }
+ };
+
+ private MonotonicClock mMonotonicClock;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ mMonotonicClock = new MonotonicClock(0, mStatsRule.getMockClock());
+ }
+
+ @Test
+ public void powerProfileModel() {
+ // ODPM unsupported
+ when(mConsumedEnergyRetriever.getEnergyConsumerIds(EnergyConsumerType.GNSS, null))
+ .thenReturn(new int[0]);
+ GnssPowerStatsProcessor processor = new GnssPowerStatsProcessor(
+ mStatsRule.getPowerProfile(), mUidResolver);
+
+ PowerComponentAggregatedPowerStats stats = createAggregatedPowerStats(processor);
+
+ GnssPowerStatsCollector collector = new GnssPowerStatsCollector(mInjector);
+ collector.addConsumer(
+ powerStats -> {
+ processor.addPowerStats(stats, powerStats, mMonotonicClock.monotonicTime());
+ });
+ collector.setEnabled(true);
+
+ // Establish a baseline
+ collector.collectAndDeliverStats();
+
+ processor.noteStateChange(stats, buildHistoryItem(0, true, APP_UID1));
+
+ // Turn the screen off after 2.5 seconds
+ stats.setState(STATE_SCREEN, SCREEN_STATE_OTHER, 2500);
+ stats.setUidState(APP_UID1, STATE_PROCESS_STATE, PROCESS_STATE_BACKGROUND, 2500);
+ stats.setUidState(APP_UID1, STATE_PROCESS_STATE, PROCESS_STATE_FOREGROUND_SERVICE, 5000);
+
+ processor.noteStateChange(stats, buildHistoryItem(6000, false, APP_UID1));
+
+ collector.collectAndDeliverStats();
+
+ processor.noteStateChange(stats, buildHistoryItem(7000, true, APP_UID2));
+ processor.noteStateChange(stats, buildHistoryItem(7000,
+ GnssSignalQuality.GNSS_SIGNAL_QUALITY_GOOD));
+ processor.noteStateChange(stats, buildHistoryItem(8000,
+ GnssSignalQuality.GNSS_SIGNAL_QUALITY_POOR));
+ mStatsRule.setTime(11_000, 11_000);
+ collector.collectAndDeliverStats();
+
+ processor.finish(stats, 11_000);
+
+ PowerStats.Descriptor descriptor = stats.getPowerStatsDescriptor();
+ BinaryStatePowerStatsLayout statsLayout = new BinaryStatePowerStatsLayout();
+ statsLayout.fromExtras(descriptor.extras);
+
+ // scr-on, GNSS-good: 2500 * 100 = 250000 mA-ms = 0.06944 mAh
+ // scr-off GNSS=good: 4500 * 100 = 0.12500 mAh
+ // scr-off GNSS=poor: 3000 * 1000 = 0.83333 mAh
+ // scr-off GNSS-on: 0.12500 + 0.83333 = 0.95833 mAh
+ long[] deviceStats = new long[descriptor.statsArrayLength];
+ stats.getDeviceStats(deviceStats, states(POWER_STATE_OTHER, SCREEN_STATE_ON));
+ assertThat(statsLayout.getDevicePowerEstimate(deviceStats))
+ .isWithin(PRECISION).of(0.06944);
+
+ stats.getDeviceStats(deviceStats, states(POWER_STATE_OTHER, SCREEN_STATE_OTHER));
+ assertThat(statsLayout.getDevicePowerEstimate(deviceStats))
+ .isWithin(PRECISION).of(0.12500 + 0.83333);
+
+ // UID1 =
+ // scr-on FG: 2500 -> 0.06944 mAh
+ // scr-off BG: 2500/7500 * 0.95833 = 0.31944 mAh
+ // scr-off FGS: 1000/7500 * 0.95833 = 0.12777 mAh
+ long[] uidStats = new long[descriptor.uidStatsArrayLength];
+ stats.getUidStats(uidStats, APP_UID1,
+ states(POWER_STATE_OTHER, SCREEN_STATE_ON, PROCESS_STATE_FOREGROUND));
+ assertThat(statsLayout.getUidPowerEstimate(uidStats))
+ .isWithin(PRECISION).of(0.06944);
+
+ stats.getUidStats(uidStats, APP_UID1,
+ states(POWER_STATE_OTHER, SCREEN_STATE_OTHER, PROCESS_STATE_BACKGROUND));
+ assertThat(statsLayout.getUidPowerEstimate(uidStats))
+ .isWithin(PRECISION).of(0.31944);
+
+ stats.getUidStats(uidStats, APP_UID1,
+ states(POWER_STATE_OTHER, SCREEN_STATE_OTHER, PROCESS_STATE_FOREGROUND_SERVICE));
+ assertThat(statsLayout.getUidPowerEstimate(uidStats))
+ .isWithin(PRECISION).of(0.12777);
+
+ // UID2 =
+ // scr-off cached: 4000/7500 * 0.95833 = 0.51111 mAh
+ stats.getUidStats(uidStats, APP_UID2,
+ states(POWER_STATE_OTHER, SCREEN_STATE_OTHER, PROCESS_STATE_CACHED));
+ assertThat(statsLayout.getUidPowerEstimate(uidStats))
+ .isWithin(PRECISION).of(0.51111);
+
+ stats.getUidStats(uidStats, APP_UID2,
+ states(POWER_STATE_OTHER, SCREEN_STATE_ON, PROCESS_STATE_CACHED));
+ assertThat(statsLayout.getUidPowerEstimate(uidStats))
+ .isWithin(PRECISION).of(0);
+ }
+
+ @Test
+ public void energyConsumerModel() {
+ when(mConsumedEnergyRetriever.getEnergyConsumerIds(EnergyConsumerType.GNSS, null))
+ .thenReturn(new int[]{ENERGY_CONSUMER_ID});
+ GnssPowerStatsProcessor processor = new GnssPowerStatsProcessor(
+ mStatsRule.getPowerProfile(), mUidResolver);
+
+ PowerComponentAggregatedPowerStats stats = createAggregatedPowerStats(processor);
+
+ GnssPowerStatsCollector collector = new GnssPowerStatsCollector(mInjector);
+ collector.addConsumer(
+ powerStats -> {
+ processor.addPowerStats(stats, powerStats, mMonotonicClock.monotonicTime());
+ });
+ collector.setEnabled(true);
+
+ // Establish a baseline
+ when(mConsumedEnergyRetriever.getConsumedEnergyUws(new int[]{ENERGY_CONSUMER_ID}))
+ .thenReturn(new long[]{uCtoUj(10000)});
+ collector.collectAndDeliverStats();
+
+ processor.noteStateChange(stats, buildHistoryItem(0, true, APP_UID1));
+
+ // Turn the screen off after 2.5 seconds
+ stats.setState(STATE_SCREEN, SCREEN_STATE_OTHER, 2500);
+ stats.setUidState(APP_UID1, STATE_PROCESS_STATE, PROCESS_STATE_BACKGROUND, 2500);
+ stats.setUidState(APP_UID1, STATE_PROCESS_STATE, PROCESS_STATE_FOREGROUND_SERVICE, 5000);
+
+ processor.noteStateChange(stats, buildHistoryItem(6000, false, APP_UID1));
+
+ when(mConsumedEnergyRetriever.getConsumedEnergyUws(new int[]{ENERGY_CONSUMER_ID}))
+ .thenReturn(new long[]{uCtoUj(2_170_000)});
+ collector.collectAndDeliverStats();
+
+ processor.noteStateChange(stats, buildHistoryItem(7000, true, APP_UID2));
+ processor.noteStateChange(stats, buildHistoryItem(7000,
+ GnssSignalQuality.GNSS_SIGNAL_QUALITY_GOOD));
+ processor.noteStateChange(stats, buildHistoryItem(8000,
+ GnssSignalQuality.GNSS_SIGNAL_QUALITY_POOR));
+ mStatsRule.setTime(11_000, 11_000);
+ when(mConsumedEnergyRetriever.getConsumedEnergyUws(new int[]{ENERGY_CONSUMER_ID}))
+ .thenReturn(new long[]{uCtoUj(3_610_000)});
+ collector.collectAndDeliverStats();
+
+ processor.finish(stats, 11_000);
+
+ PowerStats.Descriptor descriptor = stats.getPowerStatsDescriptor();
+ BinaryStatePowerStatsLayout statsLayout = new BinaryStatePowerStatsLayout();
+ statsLayout.fromExtras(descriptor.extras);
+
+ // Total estimated power = 3,600,000 uC = 1.0 mAh
+ // of which 3,000,000 is distributed:
+ // Screen-on - 2500/6000 * 2160000 = 900000 uC = 0.25 mAh
+ // Screen-off - 3500/6000 * 2160000 = 1260000 uC = 0.35 mAh
+ // and 600,000 was fully with screen off:
+ // Screen-off - 1440000 uC = 0.4 mAh
+ long[] deviceStats = new long[descriptor.statsArrayLength];
+ stats.getDeviceStats(deviceStats, states(POWER_STATE_OTHER, SCREEN_STATE_ON));
+ assertThat(statsLayout.getDevicePowerEstimate(deviceStats))
+ .isWithin(PRECISION).of(0.25);
+
+ stats.getDeviceStats(deviceStats, states(POWER_STATE_OTHER, SCREEN_STATE_OTHER));
+ assertThat(statsLayout.getDevicePowerEstimate(deviceStats))
+ .isWithin(PRECISION).of(0.35 + 0.4);
+
+ // UID1 =
+ // 2,160,000 uC = 0.6 mAh
+ // split between three different states
+ // fg screen-on: 2500/6000
+ // bg screen-off: 2500/6000
+ // fgs screen-off: 1000/6000
+ double expectedPower1 = 0.6;
+ long[] uidStats = new long[descriptor.uidStatsArrayLength];
+ stats.getUidStats(uidStats, APP_UID1,
+ states(POWER_STATE_OTHER, SCREEN_STATE_ON, PROCESS_STATE_FOREGROUND));
+ assertThat(statsLayout.getUidPowerEstimate(uidStats))
+ .isWithin(PRECISION).of(expectedPower1 * 2500 / 6000);
+
+ stats.getUidStats(uidStats, APP_UID1,
+ states(POWER_STATE_OTHER, SCREEN_STATE_OTHER, PROCESS_STATE_BACKGROUND));
+ assertThat(statsLayout.getUidPowerEstimate(uidStats))
+ .isWithin(PRECISION).of(expectedPower1 * 2500 / 6000);
+
+ stats.getUidStats(uidStats, APP_UID1,
+ states(POWER_STATE_OTHER, SCREEN_STATE_OTHER, PROCESS_STATE_FOREGROUND_SERVICE));
+ assertThat(statsLayout.getUidPowerEstimate(uidStats))
+ .isWithin(PRECISION).of(expectedPower1 * 1000 / 6000);
+
+ // UID2 =
+ // 1440000 mA-ms = 0.4 mAh
+ // all in the same state
+ double expectedPower2 = 0.4;
+ stats.getUidStats(uidStats, APP_UID2,
+ states(POWER_STATE_OTHER, SCREEN_STATE_OTHER, PROCESS_STATE_CACHED));
+ assertThat(statsLayout.getUidPowerEstimate(uidStats))
+ .isWithin(PRECISION).of(expectedPower2);
+
+ stats.getUidStats(uidStats, APP_UID2,
+ states(POWER_STATE_OTHER, SCREEN_STATE_ON, PROCESS_STATE_CACHED));
+ assertThat(statsLayout.getUidPowerEstimate(uidStats))
+ .isWithin(PRECISION).of(0);
+ }
+
+ private BatteryStats.HistoryItem buildHistoryItem(int timestamp, boolean stateOn,
+ int uid) {
+ mStatsRule.setTime(timestamp, timestamp);
+ BatteryStats.HistoryItem historyItem = new BatteryStats.HistoryItem();
+ historyItem.time = mMonotonicClock.monotonicTime();
+ historyItem.states = stateOn ? BatteryStats.HistoryItem.STATE_GPS_ON_FLAG : 0;
+ if (stateOn) {
+ historyItem.eventCode = BatteryStats.HistoryItem.EVENT_STATE_CHANGE
+ | BatteryStats.HistoryItem.EVENT_FLAG_START;
+ } else {
+ historyItem.eventCode = BatteryStats.HistoryItem.EVENT_STATE_CHANGE
+ | BatteryStats.HistoryItem.EVENT_FLAG_FINISH;
+ }
+ historyItem.eventTag = historyItem.localEventTag;
+ historyItem.eventTag.uid = uid;
+ historyItem.eventTag.string = "gnss";
+ return historyItem;
+ }
+
+ private BatteryStats.HistoryItem buildHistoryItem(int timestamp, int signalLevel) {
+ mStatsRule.setTime(timestamp, timestamp);
+ BatteryStats.HistoryItem historyItem = new BatteryStats.HistoryItem();
+ historyItem.time = mMonotonicClock.monotonicTime();
+ historyItem.states = BatteryStats.HistoryItem.STATE_GPS_ON_FLAG;
+ historyItem.states2 =
+ signalLevel << BatteryStats.HistoryItem.STATE2_GPS_SIGNAL_QUALITY_SHIFT;
+ return historyItem;
+ }
+
+ private int[] states(int... states) {
+ return states;
+ }
+
+ private static PowerComponentAggregatedPowerStats createAggregatedPowerStats(
+ BinaryStatePowerStatsProcessor processor) {
+ AggregatedPowerStatsConfig config = new AggregatedPowerStatsConfig();
+ config.trackPowerComponent(BatteryConsumer.POWER_COMPONENT_GNSS)
+ .trackDeviceStates(
+ AggregatedPowerStatsConfig.STATE_POWER,
+ AggregatedPowerStatsConfig.STATE_SCREEN)
+ .trackUidStates(
+ AggregatedPowerStatsConfig.STATE_POWER,
+ AggregatedPowerStatsConfig.STATE_SCREEN,
+ AggregatedPowerStatsConfig.STATE_PROCESS_STATE)
+ .setProcessor(processor);
+
+ AggregatedPowerStats aggregatedPowerStats = new AggregatedPowerStats(config);
+ PowerComponentAggregatedPowerStats powerComponentStats =
+ aggregatedPowerStats.getPowerComponentStats(BatteryConsumer.POWER_COMPONENT_GNSS);
+ processor.start(powerComponentStats, 0);
+
+ powerComponentStats.setState(STATE_POWER, POWER_STATE_OTHER, 0);
+ powerComponentStats.setState(STATE_SCREEN, SCREEN_STATE_ON, 0);
+ powerComponentStats.setUidState(APP_UID1, STATE_PROCESS_STATE, PROCESS_STATE_FOREGROUND, 0);
+ powerComponentStats.setUidState(APP_UID2, STATE_PROCESS_STATE, PROCESS_STATE_CACHED, 0);
+
+ return powerComponentStats;
+ }
+
+ private static long uCtoUj(long uc) {
+ return (long) (uc * (double) VOLTAGE_MV / 1000);
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageTest.java
old mode 100755
new mode 100644
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
old mode 100755
new mode 100644
diff --git a/services/tests/vibrator/src/com/android/server/vibrator/VibrationThreadTest.java b/services/tests/vibrator/src/com/android/server/vibrator/VibrationThreadTest.java
index 19ce217..9dac23f 100644
--- a/services/tests/vibrator/src/com/android/server/vibrator/VibrationThreadTest.java
+++ b/services/tests/vibrator/src/com/android/server/vibrator/VibrationThreadTest.java
@@ -1681,7 +1681,7 @@
.addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK)
.compose();
VibrationEffect effect4 = VibrationEffect.createOneShot(8000, 100);
- VibrationEffect effect5 = VibrationEffect.createOneShot(20, 222);
+ VibrationEffect effect5 = VibrationEffect.get(VibrationEffect.EFFECT_CLICK);
long vibrationId1 = startThreadAndDispatcher(effect1);
waitForCompletion();
@@ -1745,13 +1745,12 @@
verifyCallbacksTriggered(vibrationId4, Vibration.Status.CANCELLED_BY_SCREEN_OFF);
assertTrue("Tested duration=" + duration4, duration4 < 2000);
- // Effect5: normal oneshot. Don't worry about amplitude, as effect4 may or may not have
- // started.
+ // Effect5: played normally after effect4, which may or may not have played.
verify(mControllerCallbacks).onComplete(eq(VIBRATOR_ID), eq(vibrationId5));
verifyCallbacksTriggered(vibrationId5, Vibration.Status.FINISHED);
- assertEquals(Arrays.asList(expectedOneShot(20)),
+ assertEquals(Arrays.asList(expectedPrebaked(VibrationEffect.EFFECT_CLICK)),
fakeVibrator.getEffectSegments(vibrationId5));
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index 1fd8f50..ff1c6c8 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -95,6 +95,8 @@
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
import android.platform.test.annotations.Presubmit;
import android.provider.DeviceConfig;
import android.service.voice.IVoiceInteractionSession;
@@ -112,6 +114,7 @@
import com.android.server.wm.BackgroundActivityStartController.BalVerdict;
import com.android.server.wm.LaunchParamsController.LaunchParamsModifier;
import com.android.server.wm.utils.MockTracker;
+import com.android.wm.shell.Flags;
import org.junit.After;
import org.junit.Before;
@@ -492,7 +495,8 @@
// Start activity and delivered new intent.
starter.getIntent().setComponent(splitSecondReusableActivity.mActivityComponent);
- doReturn(splitSecondReusableActivity).when(mRootWindowContainer).findTask(any(), any());
+ doReturn(splitSecondReusableActivity)
+ .when(mRootWindowContainer).findTask(any(), any(), anyBoolean());
final int result = starter.setReason("testSplitScreenDeliverToTop").execute();
// Ensure result is delivering intent to top.
@@ -519,7 +523,8 @@
// Start activity and delivered new intent.
starter.getIntent().setComponent(splitSecondReusableActivity.mActivityComponent);
- doReturn(splitSecondReusableActivity).when(mRootWindowContainer).findTask(any(), any());
+ doReturn(splitSecondReusableActivity)
+ .when(mRootWindowContainer).findTask(any(), any(), anyBoolean());
final int result = starter.setReason("testSplitScreenMoveToFront").execute();
// Ensure result is moving task to front.
@@ -566,7 +571,7 @@
// Start activity and delivered new intent.
starter.getIntent().setComponent(activities.get(3).mActivityComponent);
- doReturn(activities.get(3)).when(mRootWindowContainer).findTask(any(), any());
+ doReturn(activities.get(3)).when(mRootWindowContainer).findTask(any(), any(), anyBoolean());
final int result = starter.setReason("testDesktopModeDeliverToTop").execute();
// Ensure result is delivering intent to top.
@@ -593,7 +598,8 @@
// Start activity and delivered new intent.
starter.getIntent().setComponent(desktopModeReusableActivity.mActivityComponent);
- doReturn(desktopModeReusableActivity).when(mRootWindowContainer).findTask(any(), any());
+ doReturn(desktopModeReusableActivity)
+ .when(mRootWindowContainer).findTask(any(), any(), anyBoolean());
final int result = starter.setReason("testDesktopModeMoveToFront").execute();
// Ensure result is moving task to front.
@@ -755,7 +761,7 @@
final ActivityRecord baseActivity = new ActivityBuilder(mAtm).setCreateTask(true).build();
baseActivity.getRootTask().setWindowingMode(WINDOWING_MODE_PINNED);
- doReturn(baseActivity).when(mRootWindowContainer).findTask(any(), any());
+ doReturn(baseActivity).when(mRootWindowContainer).findTask(any(), any(), anyBoolean());
ActivityOptions rawOptions = ActivityOptions.makeBasic()
.setPendingIntentCreatorBackgroundActivityStartMode(
@@ -1648,6 +1654,120 @@
assertNotEquals(inTask, target.getTask());
}
+ @EnableFlags(Flags.FLAG_ONLY_REUSE_BUBBLED_TASK_WHEN_LAUNCHED_FROM_BUBBLE)
+ @Test
+ public void launchActivity_reusesBubbledTask() {
+ final ActivityStarter starter = prepareStarter(0, false);
+ final ActivityRecord bubbledActivity = createBubbledActivity();
+
+ // create the target activity to be launched with the same component as the bubbled activity
+ final ActivityRecord targetRecord = new ActivityBuilder(mAtm)
+ .setLaunchMode(LAUNCH_SINGLE_TASK)
+ .setComponent(ActivityBuilder.getDefaultComponent()).build();
+ starter.getIntent().setComponent(bubbledActivity.mActivityComponent);
+ startActivityInner(starter, targetRecord, bubbledActivity, null /* options */,
+ null /* inTask */, null /* inTaskFragment */);
+
+ assertEquals(bubbledActivity.getTask(), targetRecord.getTask());
+ }
+
+ @EnableFlags(Flags.FLAG_ONLY_REUSE_BUBBLED_TASK_WHEN_LAUNCHED_FROM_BUBBLE)
+ @Test
+ public void launchActivity_nullSourceRecord_doesNotReuseBubbledTask() {
+ final ActivityStarter starter = prepareStarter(0, false);
+ final ActivityRecord bubbledActivity = createBubbledActivity();
+
+ // create the target activity to be launched
+ final ActivityRecord targetRecord =
+ new ActivityBuilder(mAtm)
+ .setLaunchMode(LAUNCH_SINGLE_TASK)
+ .setComponent(ActivityBuilder.getDefaultComponent()).build();
+ starter.getIntent().setComponent(bubbledActivity.mActivityComponent);
+
+ // pass null as the source record
+ startActivityInner(starter, targetRecord, null, null /* options */,
+ null /* inTask */, null /* inTaskFragment */);
+
+ assertNotEquals(bubbledActivity.getTask(), targetRecord.getTask());
+ }
+
+ @EnableFlags(Flags.FLAG_ONLY_REUSE_BUBBLED_TASK_WHEN_LAUNCHED_FROM_BUBBLE)
+ @Test
+ public void launchActivity_nonBubbledSourceRecord_doesNotReuseBubbledTask() {
+ final ActivityStarter starter = prepareStarter(0, false);
+ final ActivityRecord bubbledActivity = createBubbledActivity();
+
+ // create a non bubbled activity
+ final ActivityRecord nonBubbleSourceRecord =
+ new ActivityBuilder(mAtm).setCreateTask(true)
+ .setLaunchMode(LAUNCH_SINGLE_TASK)
+ .setComponent(ActivityBuilder.getDefaultComponent())
+ .build();
+
+ // create the target activity to be launched
+ final ActivityRecord targetRecord =
+ new ActivityBuilder(mAtm)
+ .setLaunchMode(LAUNCH_SINGLE_TASK)
+ .setComponent(ActivityBuilder.getDefaultComponent()).build();
+ starter.getIntent().setComponent(bubbledActivity.mActivityComponent);
+
+ // use the non bubbled activity as the source
+ startActivityInner(starter, targetRecord, nonBubbleSourceRecord, null /* options */,
+ null /* inTask */, null /* inTaskFragment*/);
+
+ assertNotEquals(bubbledActivity.getTask(), targetRecord.getTask());
+ }
+
+ @DisableFlags(Flags.FLAG_ONLY_REUSE_BUBBLED_TASK_WHEN_LAUNCHED_FROM_BUBBLE)
+ @Test
+ public void launchActivity_nullSourceRecord_flagDisabled_reusesBubbledTask() {
+ final ActivityStarter starter = prepareStarter(0, false);
+ final ActivityRecord bubbledActivity = createBubbledActivity();
+
+ // create the target activity to be launched
+ final ActivityRecord targetRecord =
+ new ActivityBuilder(mAtm)
+ .setLaunchMode(LAUNCH_SINGLE_TASK)
+ .setComponent(ActivityBuilder.getDefaultComponent()).build();
+ starter.getIntent().setComponent(bubbledActivity.mActivityComponent);
+
+ // pass null as the source record
+ startActivityInner(starter, targetRecord, null, null /* options */,
+ null /* inTask */, null /* inTaskFragment */);
+
+ assertEquals(bubbledActivity.getTask(), targetRecord.getTask());
+ }
+
+ @DisableFlags(Flags.FLAG_ONLY_REUSE_BUBBLED_TASK_WHEN_LAUNCHED_FROM_BUBBLE)
+ @Test
+ public void launchActivity_fromBubble_flagDisabled_reusesBubbledTask() {
+ final ActivityStarter starter = prepareStarter(0, false);
+ final ActivityRecord bubbledActivity = createBubbledActivity();
+
+ // create the target activity to be launched with the same component as the bubbled activity
+ final ActivityRecord targetRecord =
+ new ActivityBuilder(mAtm)
+ .setLaunchMode(LAUNCH_SINGLE_TASK)
+ .setComponent(ActivityBuilder.getDefaultComponent()).build();
+ starter.getIntent().setComponent(bubbledActivity.mActivityComponent);
+ startActivityInner(starter, targetRecord, bubbledActivity, null /* options */,
+ null /* inTask */, null /* inTaskFragment */);
+
+ assertEquals(bubbledActivity.getTask(), targetRecord.getTask());
+ }
+
+ private ActivityRecord createBubbledActivity() {
+ final ActivityOptions opts = ActivityOptions.makeBasic();
+ opts.setTaskAlwaysOnTop(true);
+ opts.setLaunchedFromBubble(true);
+ opts.setLaunchBounds(new Rect(10, 10, 100, 100));
+ return new ActivityBuilder(mAtm)
+ .setCreateTask(true)
+ .setComponent(ActivityBuilder.getDefaultComponent())
+ .setActivityOptions(opts)
+ .build();
+ }
+
private static void startActivityInner(ActivityStarter starter, ActivityRecord target,
ActivityRecord source, ActivityOptions options, Task inTask,
TaskFragment inTaskFragment) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
index c67d1ec..a39a1a8 100644
--- a/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
@@ -550,7 +550,7 @@
}).when(appWindow.mSession).setOnBackInvokedCallbackInfo(eq(appWindow.mClient), any());
addToWindowMap(appWindow, true);
- dispatcher.attachToWindow(appWindow.mSession, appWindow.mClient, null, null);
+ dispatcher.attachToWindow(appWindow.mSession, appWindow.mClient, null);
OnBackInvokedCallback appCallback = createBackCallback(appLatch);
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootTaskTests.java b/services/tests/wmtests/src/com/android/server/wm/RootTaskTests.java
index ce90504..e019a41 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootTaskTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootTaskTests.java
@@ -405,11 +405,12 @@
final RootWindowContainer.FindTaskResult result =
new RootWindowContainer.FindTaskResult();
- result.init(r.getActivityType(), r.taskAffinity, r.intent, r.info);
+ result.init(r.getActivityType(), r.taskAffinity, r.intent, r.info, true);
result.process(task);
- assertEquals(r, task.getTopNonFinishingActivity(false /* includeOverlays */));
- assertEquals(taskOverlay, task.getTopNonFinishingActivity(true /* includeOverlays */));
+ assertEquals(r, task.getTopNonFinishingActivity(false /* includeOverlays */, true));
+ assertEquals(
+ taskOverlay, task.getTopNonFinishingActivity(true /* includeOverlays */, true));
assertNotNull(result.mIdealRecord);
}
@@ -432,7 +433,7 @@
final ActivityRecord r1 = new ActivityBuilder(mAtm).setComponent(
target).setTargetActivity(targetActivity).build();
RootWindowContainer.FindTaskResult result = new RootWindowContainer.FindTaskResult();
- result.init(r1.getActivityType(), r1.taskAffinity, r1.intent, r1.info);
+ result.init(r1.getActivityType(), r1.taskAffinity, r1.intent, r1.info, true);
result.process(parentTask);
assertThat(result.mIdealRecord).isNotNull();
@@ -440,7 +441,7 @@
final ActivityRecord r2 = new ActivityBuilder(mAtm).setComponent(
alias).setTargetActivity(targetActivity).build();
result = new RootWindowContainer.FindTaskResult();
- result.init(r2.getActivityType(), r2.taskAffinity, r2.intent, r2.info);
+ result.init(r2.getActivityType(), r2.taskAffinity, r2.intent, r2.info, true);
result.process(parentTask);
assertThat(result.mIdealRecord).isNotNull();
}
@@ -1234,12 +1235,18 @@
assertEquals(STOPPING, activity2.getState());
assertThat(mSupervisor.mStoppingActivities).contains(activity2);
+ registerTestTransitionPlayer();
+ final Transition transition = display.mTransitionController
+ .requestCloseTransitionIfNeeded(rootTask1);
+ transition.collectClose(rootTask1);
// The display becomes empty. Since there is no next activity to be idle, the activity
// should be destroyed immediately with updating configuration to restore original state.
final ActivityRecord activity1 = finishTopActivity(rootTask1);
assertEquals(DESTROYING, activity1.getState());
verify(mRootWindowContainer).ensureVisibilityAndConfig(eq(null) /* starting */,
eq(display), anyBoolean());
+ assertTrue("Transition must be ready if there is no next running activity",
+ transition.allReady());
}
private ActivityRecord finishTopActivity(Task task) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
index d88871c..eb79118 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
@@ -147,6 +147,40 @@
}
@Test
+ public void testFindTask_includeLaunchedFromBubbled() {
+ final ComponentName component = ComponentName.createRelative(
+ DEFAULT_COMPONENT_PACKAGE_NAME, ".BubbledActivity");
+ final ActivityOptions opts = ActivityOptions.makeBasic();
+ opts.setTaskAlwaysOnTop(true);
+ opts.setLaunchedFromBubble(true);
+ final ActivityRecord activity = new ActivityBuilder(mWm.mAtmService)
+ .setComponent(component)
+ .setActivityOptions(opts)
+ .setCreateTask(true)
+ .build();
+
+ assertEquals(activity, mWm.mRoot.findTask(activity, activity.getTaskDisplayArea(),
+ true /* includeLaunchedFromBubble */));
+ }
+
+ @Test
+ public void testFindTask_ignoreLaunchedFromBubbled() {
+ final ComponentName component = ComponentName.createRelative(
+ DEFAULT_COMPONENT_PACKAGE_NAME, ".BubbledActivity");
+ final ActivityOptions opts = ActivityOptions.makeBasic();
+ opts.setTaskAlwaysOnTop(true);
+ opts.setLaunchedFromBubble(true);
+ final ActivityRecord activity = new ActivityBuilder(mWm.mAtmService)
+ .setComponent(component)
+ .setActivityOptions(opts)
+ .setCreateTask(true)
+ .build();
+
+ assertNull(mWm.mRoot.findTask(activity, activity.getTaskDisplayArea(),
+ false /* includeLaunchedFromBubble */));
+ }
+
+ @Test
public void testAllPausedActivitiesComplete() {
DisplayContent displayContent = mWm.mRoot.getDisplayContent(DEFAULT_DISPLAY);
ActivityRecord activity = createActivityRecord(displayContent);
diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
index 7adac5b..1a366b3 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -105,7 +105,6 @@
import android.os.UserHandle;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.annotations.Presubmit;
-import android.platform.test.annotations.RequiresFlagsDisabled;
import android.provider.DeviceConfig;
import android.provider.DeviceConfig.Properties;
import android.view.InsetsFrameProvider;
@@ -339,10 +338,9 @@
}
}
- // TODO(b/333663877): Enable test after fix
@Test
- @RequiresFlagsDisabled({Flags.FLAG_INSETS_DECOUPLED_CONFIGURATION})
@EnableFlags(Flags.FLAG_IMMERSIVE_APP_REPOSITIONING)
+ @DisableCompatChanges({ActivityInfo.INSETS_DECOUPLED_CONFIGURATION_ENFORCED})
public void testRepositionLandscapeImmersiveAppWithDisplayCutout() {
final int dw = 2100;
final int dh = 2000;
@@ -356,11 +354,14 @@
mWm.mLetterboxConfiguration.setLetterboxVerticalPositionMultiplier(0.5f);
mWm.mLetterboxConfiguration.setIsVerticalReachabilityEnabled(true);
- doReturn(true).when(mActivity).isImmersiveMode(any());
- prepareMinAspectRatio(mActivity, OVERRIDE_MIN_ASPECT_RATIO_LARGE_VALUE,
- SCREEN_ORIENTATION_LANDSCAPE);
- addWindowToActivity(mActivity);
- mActivity.mRootWindowContainer.performSurfacePlacement();
+ final ActivityRecord activity = getActivityBuilderOnSameTask()
+ .setScreenOrientation(SCREEN_ORIENTATION_LANDSCAPE)
+ .setMinAspectRatio(OVERRIDE_MIN_ASPECT_RATIO_LARGE_VALUE)
+ .build();
+
+ doReturn(true).when(activity).isImmersiveMode(any());
+ addWindowToActivity(activity);
+ activity.mRootWindowContainer.performSurfacePlacement();
final Function<ActivityRecord, Rect> innerBoundsOf =
(ActivityRecord a) -> {
@@ -371,22 +372,22 @@
final Consumer<Integer> doubleClick =
(Integer y) -> {
- mActivity.mLetterboxUiController.handleVerticalDoubleTap(y);
- mActivity.mRootWindowContainer.performSurfacePlacement();
+ activity.mLetterboxUiController.handleVerticalDoubleTap(y);
+ activity.mRootWindowContainer.performSurfacePlacement();
};
- final Rect bounds = mActivity.getBounds();
+ final Rect bounds = activity.getBounds();
assertTrue(bounds.top > cutoutHeight && bounds.bottom < dh);
assertEquals(dw, bounds.width());
// Double click bottom.
doubleClick.accept(dh - 10);
- assertEquals(dh, innerBoundsOf.apply(mActivity).bottom);
+ assertEquals(dh, innerBoundsOf.apply(activity).bottom);
// Double click top.
doubleClick.accept(10);
doubleClick.accept(10);
- assertEquals(cutoutHeight, innerBoundsOf.apply(mActivity).top);
+ assertEquals(cutoutHeight, innerBoundsOf.apply(activity).top);
}
@Test
@@ -417,26 +418,25 @@
}
@Test
+ @DisableCompatChanges({ActivityInfo.INSETS_DECOUPLED_CONFIGURATION_ENFORCED})
public void testFixedAspectRatioBoundsWithDecorInSquareDisplay() {
- if (Flags.insetsDecoupledConfiguration()) {
- // TODO (b/151861875): Re-enable it. This is disabled temporarily because the config
- // bounds no longer contains display cutout.
- return;
- }
final int notchHeight = 100;
setUpApp(new TestDisplayContent.Builder(mAtm, 600, 800).setNotch(notchHeight).build());
final Rect displayBounds = mActivity.mDisplayContent.getWindowConfiguration().getBounds();
final float aspectRatio = 1.2f;
- mActivity.info.setMaxAspectRatio(aspectRatio);
- mActivity.info.setMinAspectRatio(aspectRatio);
- prepareUnresizable(mActivity, -1f, SCREEN_ORIENTATION_UNSPECIFIED);
- final Rect appBounds = mActivity.getWindowConfiguration().getAppBounds();
+ final ActivityRecord activity = getActivityBuilderOnSameTask()
+ .setScreenOrientation(SCREEN_ORIENTATION_UNSPECIFIED)
+ .setMinAspectRatio(aspectRatio)
+ .setMaxAspectRatio(aspectRatio)
+ .setResizeMode(RESIZE_MODE_UNRESIZEABLE)
+ .build();
+ final Rect appBounds = activity.getWindowConfiguration().getAppBounds();
// The parent configuration doesn't change since the first resolved configuration, so the
// activity should fit in the parent naturally (size=583x700, appBounds=[9, 100 - 592, 800],
// horizontal offset = round((600 - 583) / 2) = 9)).
- assertFitted();
+ assertFitted(activity);
final int offsetX = (int) ((1f + displayBounds.width() - appBounds.width()) / 2);
// The bounds must be horizontal centered.
assertEquals(offsetX, appBounds.left);
@@ -444,30 +444,30 @@
// Ensure the app bounds keep the declared aspect ratio.
assertEquals(appBounds.height(), appBounds.width() * aspectRatio, 0.5f /* delta */);
// The decor height should be a part of the effective bounds.
- assertEquals(mActivity.getBounds().height(), appBounds.height() + notchHeight);
+ assertEquals(activity.getBounds().height(), appBounds.height() + notchHeight);
// Activity max bounds should be sandboxed; activity is letterboxed due to aspect ratio.
- assertActivityMaxBoundsSandboxed();
+ assertActivityMaxBoundsSandboxed(activity);
// Activity max bounds ignore notch, since an app can be shown past the notch (although app
// is currently limited by the notch).
- assertThat(mActivity.getWindowConfiguration().getMaxBounds().height())
+ assertThat(activity.getWindowConfiguration().getMaxBounds().height())
.isEqualTo(displayBounds.height());
- mActivity.setRequestedOrientation(SCREEN_ORIENTATION_LANDSCAPE);
- assertFitted();
+ activity.setRequestedOrientation(SCREEN_ORIENTATION_LANDSCAPE);
+ assertFitted(activity);
// After the orientation of activity is changed, the display is rotated, the aspect
// ratio should be the same (bounds=[0, 0 - 800, 583], appBounds=[100, 0 - 800, 583]).
assertEquals(appBounds.width(), appBounds.height() * aspectRatio, 0.5f /* delta */);
// Activity max bounds are sandboxed.
- assertActivityMaxBoundsSandboxed();
+ assertActivityMaxBoundsSandboxed(activity);
- mActivity.setRequestedOrientation(SCREEN_ORIENTATION_PORTRAIT);
- assertFitted();
+ activity.setRequestedOrientation(SCREEN_ORIENTATION_PORTRAIT);
+ assertFitted(activity);
// Activity max bounds should be sandboxed; activity is letterboxed due to aspect ratio.
- assertActivityMaxBoundsSandboxed();
+ assertActivityMaxBoundsSandboxed(activity);
// Activity max bounds ignore notch, since an app can be shown past the notch (although app
// is currently limited by the notch).
- assertThat(mActivity.getWindowConfiguration().getMaxBounds().height())
+ assertThat(activity.getWindowConfiguration().getMaxBounds().height())
.isEqualTo(displayBounds.height());
}
@@ -674,12 +674,8 @@
@Test
public void testMoveToDifferentOrientationDisplay() {
- if (Flags.insetsDecoupledConfiguration()) {
- // TODO (b/151861875): Re-enable it. This is disabled temporarily because the config
- // bounds no longer contains display cutout.
- return;
- }
setUpDisplaySizeWithApp(1000, 2500);
+ mActivity.mResolveConfigHint.mUseOverrideInsetsForConfig = true;
prepareUnresizable(mActivity, -1.f /* maxAspect */, SCREEN_ORIENTATION_PORTRAIT);
assertFitted();
@@ -726,16 +722,12 @@
@Test
public void testFixedOrientationRotateCutoutDisplay() {
- if (Flags.insetsDecoupledConfiguration()) {
- // TODO (b/151861875): Re-enable it. This is disabled temporarily because the config
- // bounds no longer contains display cutout.
- return;
- }
// Create a display with a notch/cutout
final int notchHeight = 60;
final int width = 1000;
setUpApp(new TestDisplayContent.Builder(mAtm, width, 2500)
.setNotch(notchHeight).build());
+ mActivity.mResolveConfigHint.mUseOverrideInsetsForConfig = true;
// Bounds=[0, 0 - 1000, 1400], AppBounds=[0, 60 - 1000, 1460].
final float maxAspect = 1.4f;
prepareUnresizable(mActivity, 1.4f /* maxAspect */, SCREEN_ORIENTATION_PORTRAIT);
@@ -1328,12 +1320,8 @@
setUpDisplaySizeWithApp(1000, 1200);
// Create a size compat activity on the same task.
- final ActivityRecord activity = new ActivityBuilder(mAtm)
- .setTask(mTask)
+ final ActivityRecord activity = getActivityBuilderOnSameTask()
.setScreenOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)
- .setComponent(ComponentName.createRelative(mContext,
- SizeCompatTests.class.getName()))
- .setUid(android.os.Process.myUid())
.build();
// The per-package override forces the activity into a 3:2 aspect ratio
@@ -1345,24 +1333,18 @@
@Test
@EnableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO,
ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_MEDIUM})
+ @DisableCompatChanges({ActivityInfo.INSETS_DECOUPLED_CONFIGURATION_ENFORCED})
public void testOverrideMinAspectRatioLowerThanManifest() {
- if (Flags.insetsDecoupledConfiguration()) {
- // TODO (b/151861875): Re-enable it. This is disabled temporarily because the config
- // bounds no longer contains display cutout.
- return;
- }
- final DisplayContent display = new TestDisplayContent.Builder(mAtm, 1400, 1800)
- .setNotch(200).setSystemDecorations(true).build();
+ final int dh = 1800;
+ final int notchHeight = 200;
+ final DisplayContent display = new TestDisplayContent.Builder(mAtm, 1400, dh)
+ .setNotch(notchHeight).setSystemDecorations(true).build();
mTask = new TaskBuilder(mSupervisor).setDisplay(display).build();
// Create a size compat activity on the same task.
- final ActivityRecord activity = new ActivityBuilder(mAtm)
- .setTask(mTask)
+ final ActivityRecord activity = getActivityBuilderOnSameTask()
.setScreenOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)
- .setComponent(ComponentName.createRelative(mContext,
- SizeCompatTests.class.getName()))
.setMinAspectRatio(2f)
- .setUid(android.os.Process.myUid())
.build();
// The per-package override should have no effect, because the manifest aspect ratio is
@@ -1371,7 +1353,7 @@
assertEquals("App bounds must have min aspect ratio", 2f,
(float) appBounds.height() / appBounds.width(), 0.0001f /* delta */);
assertEquals("Long side must fit task",
- mTask.getWindowConfiguration().getAppBounds().height(), appBounds.height());
+ dh - notchHeight, appBounds.height());
assertEquals("Bounds can include insets", mTask.getBounds().height(),
activity.getBounds().height());
}
@@ -1383,13 +1365,9 @@
setUpDisplaySizeWithApp(1400, 1600);
// Create a size compat activity on the same task.
- final ActivityRecord activity = new ActivityBuilder(mAtm)
- .setTask(mTask)
+ final ActivityRecord activity = getActivityBuilderOnSameTask()
.setScreenOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)
- .setComponent(ComponentName.createRelative(mContext,
- SizeCompatTests.class.getName()))
.setMinAspectRatio(1.1f)
- .setUid(android.os.Process.myUid())
.build();
// The per-package override should have no effect, because the manifest aspect ratio is
@@ -1406,12 +1384,8 @@
setUpDisplaySizeWithApp(1500, 1600);
// Create a size compat activity on the same task.
- final ActivityRecord activity = new ActivityBuilder(mAtm)
- .setTask(mTask)
+ final ActivityRecord activity = getActivityBuilderOnSameTask()
.setScreenOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)
- .setComponent(ComponentName.createRelative(mContext,
- SizeCompatTests.class.getName()))
- .setUid(android.os.Process.myUid())
.build();
// The per-package override forces the activity into a 16:9 aspect ratio
@@ -1430,12 +1404,8 @@
setUpDisplaySizeWithApp(1400, 1600);
// Create a size compat activity on the same task.
- final ActivityRecord activity = new ActivityBuilder(mAtm)
- .setTask(mTask)
+ final ActivityRecord activity = getActivityBuilderOnSameTask()
.setScreenOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)
- .setComponent(ComponentName.createRelative(mContext,
- SizeCompatTests.class.getName()))
- .setUid(android.os.Process.myUid())
.build();
// The per-package override forces the activity into a 16:9 aspect ratio
@@ -1455,12 +1425,7 @@
setUpDisplaySizeWithApp(1000, 1200);
// Create a size compat activity on the same task.
- final ActivityRecord activity = new ActivityBuilder(mAtm)
- .setTask(mTask)
- .setComponent(ComponentName.createRelative(mContext,
- SizeCompatTests.class.getName()))
- .setUid(android.os.Process.myUid())
- .build();
+ final ActivityRecord activity = getActivityBuilderOnSameTask().build();
// The per-package override should have no effect
assertEquals(1200, activity.getBounds().height());
@@ -1487,12 +1452,8 @@
setUpDisplaySizeWithApp(1000, 1200);
// Create a size compat activity on the same task.
- final ActivityRecord activity = new ActivityBuilder(mAtm)
- .setTask(mTask)
+ final ActivityRecord activity = getActivityBuilderOnSameTask()
.setScreenOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE)
- .setComponent(ComponentName.createRelative(mContext,
- SizeCompatTests.class.getName()))
- .setUid(android.os.Process.myUid())
.build();
// The per-package override should have no effect
@@ -1517,12 +1478,8 @@
setUpDisplaySizeWithApp(1000, 1200);
// Create a size compat activity on the same task.
- final ActivityRecord activity = new ActivityBuilder(mAtm)
- .setTask(mTask)
+ final ActivityRecord activity = getActivityBuilderOnSameTask()
.setScreenOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)
- .setComponent(ComponentName.createRelative(mContext,
- SizeCompatTests.class.getName()))
- .setUid(android.os.Process.myUid())
.build();
// The per-package override forces the activity into a 3:2 aspect ratio
@@ -1547,12 +1504,7 @@
setUpDisplaySizeWithApp(1000, 1200);
// Create a size compat activity on the same task.
- final ActivityRecord activity = new ActivityBuilder(mAtm)
- .setTask(mTask)
- .setComponent(ComponentName.createRelative(mContext,
- SizeCompatTests.class.getName()))
- .setUid(android.os.Process.myUid())
- .build();
+ final ActivityRecord activity = getActivityBuilderOnSameTask().build();
// The per-package override forces the activity into a 3:2 aspect ratio
assertEquals(1200, activity.getBounds().height());
@@ -1571,12 +1523,8 @@
setUpDisplaySizeWithApp(1000, 1200);
// Create a size compat activity on the same task.
- final ActivityRecord activity = new ActivityBuilder(mAtm)
- .setTask(mTask)
+ final ActivityRecord activity = getActivityBuilderOnSameTask()
.setScreenOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE)
- .setComponent(ComponentName.createRelative(mContext,
- SizeCompatTests.class.getName()))
- .setUid(android.os.Process.myUid())
.build();
// The per-package override forces the activity into a 3:2 aspect ratio
@@ -1594,12 +1542,8 @@
setUpDisplaySizeWithApp(1000, 1200);
// Create a size compat activity on the same task.
- final ActivityRecord activity = new ActivityBuilder(mAtm)
- .setTask(mTask)
+ final ActivityRecord activity = getActivityBuilderOnSameTask()
.setScreenOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)
- .setComponent(ComponentName.createRelative(mContext,
- SizeCompatTests.class.getName()))
- .setUid(android.os.Process.myUid())
.build();
// The per-package override should have no effect
@@ -1614,12 +1558,8 @@
setUpDisplaySizeWithApp(/* dw= */ 1000, /* dh= */ 2800);
// Create a size compat activity on the same task.
- final ActivityRecord activity = new ActivityBuilder(mAtm)
- .setTask(mTask)
+ final ActivityRecord activity = getActivityBuilderOnSameTask()
.setScreenOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)
- .setComponent(ComponentName.createRelative(mContext,
- SizeCompatTests.class.getName()))
- .setUid(android.os.Process.myUid())
.build();
final TestSplitOrganizer organizer =
@@ -1697,15 +1637,11 @@
@Test
public void testLaunchWithFixedRotationTransform() {
- if (Flags.insetsDecoupledConfiguration()) {
- // TODO (b/151861875): Re-enable it. This is disabled temporarily because the config
- // bounds no longer contains display cutout.
- return;
- }
final int dw = 1000;
final int dh = 2500;
final int notchHeight = 200;
setUpApp(new TestDisplayContent.Builder(mAtm, dw, dh).setNotch(notchHeight).build());
+ mActivity.mResolveConfigHint.mUseOverrideInsetsForConfig = true;
// The test assumes the notch will be at left side when the orientation is landscape.
if (mContext.getResources().getBoolean(
com.android.internal.R.bool.config_reverseDefaultRotation)) {
@@ -2315,12 +2251,7 @@
private void testUserOverrideAspectRatio(boolean isUnresizable, int screenOrientation,
float expectedAspectRatio, @PackageManager.UserMinAspectRatio int aspectRatio,
boolean enabled) {
- final ActivityRecord activity = new ActivityBuilder(mAtm)
- .setTask(mTask)
- .setComponent(ComponentName.createRelative(mContext,
- SizeCompatTests.class.getName()))
- .setUid(android.os.Process.myUid())
- .build();
+ final ActivityRecord activity = getActivityBuilderOnSameTask().build();
activity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
spyOn(activity.mWmService.mLetterboxConfiguration);
doReturn(enabled).when(activity.mWmService.mLetterboxConfiguration)
@@ -2351,12 +2282,8 @@
final int displayWidth = 1400;
final int displayHeight = 1600;
setUpDisplaySizeWithApp(displayWidth, displayHeight);
- final ActivityRecord activity = new ActivityBuilder(mAtm)
- .setTask(mTask)
- .setComponent(ComponentName.createRelative(mContext,
- SizeCompatTests.class.getName()))
+ final ActivityRecord activity = getActivityBuilderOnSameTask()
.setMinAspectRatio(1.1f)
- .setUid(android.os.Process.myUid())
.build();
// Setup Letterbox Configuration
activity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
@@ -2376,12 +2303,8 @@
final int displayWidth = 1600;
final int displayHeight = 1400;
setUpDisplaySizeWithApp(displayWidth, displayHeight);
- final ActivityRecord activity = new ActivityBuilder(mAtm)
- .setTask(mTask)
- .setComponent(ComponentName.createRelative(mContext,
- SizeCompatTests.class.getName()))
+ final ActivityRecord activity = getActivityBuilderOnSameTask()
.setMinAspectRatio(1.1f)
- .setUid(android.os.Process.myUid())
.build();
// Setup Letterbox Configuration
activity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
@@ -2402,12 +2325,8 @@
final int displayWidth = 1400;
final int displayHeight = 1600;
setUpDisplaySizeWithApp(displayWidth, displayHeight);
- final ActivityRecord activity = new ActivityBuilder(mAtm)
- .setTask(mTask)
- .setComponent(ComponentName.createRelative(mContext,
- SizeCompatTests.class.getName()))
+ final ActivityRecord activity = getActivityBuilderOnSameTask()
.setMinAspectRatio(1.1f)
- .setUid(android.os.Process.myUid())
.build();
// Setup Letterbox Configuration
activity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
@@ -2428,12 +2347,8 @@
final int displayWidth = 1600;
final int displayHeight = 1400;
setUpDisplaySizeWithApp(displayWidth, displayHeight);
- final ActivityRecord activity = new ActivityBuilder(mAtm)
- .setTask(mTask)
- .setComponent(ComponentName.createRelative(mContext,
- SizeCompatTests.class.getName()))
+ final ActivityRecord activity = getActivityBuilderOnSameTask()
.setMinAspectRatio(1.1f)
- .setUid(android.os.Process.myUid())
.build();
// Setup Letterbox Configuration
activity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
@@ -2454,12 +2369,7 @@
final int screenWidth = 1800;
final int screenHeight = 1000;
setUpDisplaySizeWithApp(screenWidth, screenHeight);
- final ActivityRecord activity = new ActivityBuilder(mAtm)
- .setTask(mTask)
- .setComponent(ComponentName.createRelative(mContext,
- SizeCompatTests.class.getName()))
- .setUid(android.os.Process.myUid())
- .build();
+ final ActivityRecord activity = getActivityBuilderOnSameTask().build();
activity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
// Simulate real display with top insets.
@@ -2495,12 +2405,7 @@
final int screenWidth = 1000;
final int screenHeight = 1800;
setUpDisplaySizeWithApp(screenWidth, screenHeight);
- final ActivityRecord activity = new ActivityBuilder(mAtm)
- .setTask(mTask)
- .setComponent(ComponentName.createRelative(mContext,
- SizeCompatTests.class.getName()))
- .setUid(android.os.Process.myUid())
- .build();
+ final ActivityRecord activity = getActivityBuilderOnSameTask().build();
activity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
// Simulate real display with top insets.
@@ -2538,12 +2443,7 @@
mActivity.mWmService.mLetterboxConfiguration.setFixedOrientationLetterboxAspectRatio(1.33f);
// Create a size compat activity on the same task.
- final ActivityRecord activity = new ActivityBuilder(mAtm)
- .setTask(mTask)
- .setComponent(ComponentName.createRelative(mContext,
- SizeCompatTests.class.getName()))
- .setUid(android.os.Process.myUid())
- .build();
+ final ActivityRecord activity = getActivityBuilderOnSameTask().build();
// Non-resizable portrait activity
prepareUnresizable(activity, 0f, ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
@@ -2573,12 +2473,7 @@
mActivity.mWmService.mLetterboxConfiguration.setFixedOrientationLetterboxAspectRatio(1.33f);
// Create a size compat activity on the same task.
- final ActivityRecord activity = new ActivityBuilder(mAtm)
- .setTask(mTask)
- .setComponent(ComponentName.createRelative(mContext,
- SizeCompatTests.class.getName()))
- .setUid(android.os.Process.myUid())
- .build();
+ final ActivityRecord activity = getActivityBuilderOnSameTask().build();
final TestSplitOrganizer organizer =
new TestSplitOrganizer(mAtm, activity.getDisplayContent());
@@ -3636,17 +3531,13 @@
@Test
public void testLetterboxDetailsForStatusBar_letterboxNotOverlappingStatusBar() {
- if (Flags.insetsDecoupledConfiguration()) {
- // TODO (b/151861875): Re-enable it. This is disabled temporarily because the config
- // bounds no longer contains display cutout.
- return;
- }
// Align to center so that we don't overlap with the status bar
mAtm.mWindowManager.mLetterboxConfiguration.setLetterboxVerticalPositionMultiplier(0.5f);
final DisplayContent display = new TestDisplayContent.Builder(mAtm, 1000, 2800)
.setNotch(100)
.build();
setUpApp(display);
+ mActivity.mResolveConfigHint.mUseOverrideInsetsForConfig = true;
TestWindowState statusBar = addStatusBar(mActivity.mDisplayContent);
spyOn(statusBar);
doReturn(new Rect(0, 0, statusBar.mRequestedWidth, statusBar.mRequestedHeight))
@@ -3658,12 +3549,12 @@
// Refresh the letterbox
mActivity.mRootWindowContainer.performSurfacePlacement();
- Rect mBounds = new Rect(mActivity.getWindowConfiguration().getBounds());
- assertEquals(mBounds, new Rect(0, 900, 1000, 2000));
+ Rect bounds = new Rect(mActivity.getWindowConfiguration().getBounds());
+ assertEquals(new Rect(0, 900, 1000, 2000), bounds);
DisplayPolicy displayPolicy = mActivity.getDisplayContent().getDisplayPolicy();
LetterboxDetails[] expectedLetterboxDetails = {new LetterboxDetails(
- mBounds,
+ bounds,
mActivity.getDisplayContent().getBounds(),
mActivity.findMainWindow().mAttrs.insetsFlags.appearance
)};
@@ -3952,12 +3843,8 @@
assertTrue(display.getDisplayPolicy().updateDecorInsetsInfo());
display.sendNewConfiguration();
- final ActivityRecord activity = new ActivityBuilder(mAtm)
- .setTask(mTask)
+ final ActivityRecord activity = getActivityBuilderOnSameTask()
.setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT)
- .setComponent(ComponentName.createRelative(mContext,
- SizeCompatTests.class.getName()))
- .setUid(android.os.Process.myUid())
.build();
// Activity should not be letterboxed and should have portrait app bounds even though
@@ -3989,12 +3876,8 @@
assertTrue(display.getDisplayPolicy().updateDecorInsetsInfo());
display.sendNewConfiguration();
- final ActivityRecord activity = new ActivityBuilder(mAtm)
- .setTask(mTask)
+ final ActivityRecord activity = getActivityBuilderOnSameTask()
.setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT)
- .setComponent(ComponentName.createRelative(mContext,
- SizeCompatTests.class.getName()))
- .setUid(android.os.Process.myUid())
.build();
final Rect bounds = activity.getBounds();
@@ -4021,14 +3904,11 @@
assertTrue(dc.getDisplayPolicy().updateDecorInsetsInfo());
dc.sendNewConfiguration();
- final ActivityRecord activity = new ActivityBuilder(mAtm)
- .setTask(mTask)
- .setComponent(ComponentName.createRelative(mContext,
- SizeCompatTests.class.getName()))
- .setUid(android.os.Process.myUid())
+ final ActivityRecord activity = getActivityBuilderOnSameTask()
+ .setResizeMode(RESIZE_MODE_UNRESIZEABLE)
+ .setScreenOrientation(SCREEN_ORIENTATION_LANDSCAPE)
+ .setMinAspectRatio(OVERRIDE_MIN_ASPECT_RATIO_LARGE_VALUE)
.build();
- prepareMinAspectRatio(activity, OVERRIDE_MIN_ASPECT_RATIO_LARGE_VALUE,
- SCREEN_ORIENTATION_LANDSCAPE);
// To force config to update again but with the same landscape orientation.
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE);
@@ -4042,11 +3922,6 @@
@Test
public void testApplyAspectRatio_activityAlignWithParentAppVertical() {
- if (Flags.insetsDecoupledConfiguration()) {
- // TODO (b/151861875): Re-enable it. This is disabled temporarily because the config
- // bounds no longer contains display cutout.
- return;
- }
// The display's app bounds will be (0, 100, 1000, 2350)
final DisplayContent display = new TestDisplayContent.Builder(mAtm, 1000, 2500)
.setCanRotate(false)
@@ -4054,19 +3929,16 @@
.build();
setUpApp(display);
- prepareUnresizable(mActivity, 2.1f /* maxAspect */, SCREEN_ORIENTATION_UNSPECIFIED);
+ mActivity.mResolveConfigHint.mUseOverrideInsetsForConfig = true;
+ prepareUnresizable(mActivity, 2.1f, SCREEN_ORIENTATION_UNSPECIFIED);
// The activity height is 2100 and the display's app bounds height is 2250, so the activity
// can be aligned inside parentAppBounds
- assertEquals(mActivity.getBounds(), new Rect(0, 0, 1000, 2200));
+ assertEquals(new Rect(0, 0, 1000, 2200), mActivity.getBounds());
}
@Test
+ @DisableCompatChanges({ActivityInfo.INSETS_DECOUPLED_CONFIGURATION_ENFORCED})
public void testApplyAspectRatio_activityCannotAlignWithParentAppVertical() {
- if (Flags.insetsDecoupledConfiguration()) {
- // TODO (b/151861875): Re-enable it. This is disabled temporarily because the config
- // bounds no longer contains display cutout.
- return;
- }
// The display's app bounds will be (0, 100, 1000, 2150)
final DisplayContent display = new TestDisplayContent.Builder(mAtm, 1000, 2300)
.setCanRotate(false)
@@ -4074,19 +3946,21 @@
.build();
setUpApp(display);
- prepareUnresizable(mActivity, 2.1f /* maxAspect */, SCREEN_ORIENTATION_UNSPECIFIED);
+
+ final ActivityRecord activity = getActivityBuilderOnSameTask()
+ .setResizeMode(RESIZE_MODE_UNRESIZEABLE)
+ .setMaxAspectRatio(2.1f)
+ .setScreenOrientation(SCREEN_ORIENTATION_UNSPECIFIED)
+ .build();
+
// The activity height is 2100 and the display's app bounds height is 2050, so the activity
// cannot be aligned inside parentAppBounds and it will fill the parentBounds of the display
- assertEquals(mActivity.getBounds(), display.getBounds());
+ assertEquals(activity.getBounds(), display.getBounds());
}
@Test
+ @DisableCompatChanges({ActivityInfo.INSETS_DECOUPLED_CONFIGURATION_ENFORCED})
public void testApplyAspectRatio_activityAlignWithParentAppHorizontal() {
- if (Flags.insetsDecoupledConfiguration()) {
- // TODO (b/151861875): Re-enable it. This is disabled temporarily because the config
- // bounds no longer contains display cutout.
- return;
- }
// The display's app bounds will be (100, 0, 2350, 1000)
final DisplayContent display = new TestDisplayContent.Builder(mAtm, 2500, 1000)
.setCanRotate(false)
@@ -4094,18 +3968,19 @@
.build();
setUpApp(display);
- prepareUnresizable(mActivity, 2.1f /* maxAspect */, SCREEN_ORIENTATION_UNSPECIFIED);
+
+ final ActivityRecord activity = getActivityBuilderOnSameTask()
+ .setResizeMode(RESIZE_MODE_UNRESIZEABLE)
+ .setMaxAspectRatio(2.1f)
+ .setScreenOrientation(SCREEN_ORIENTATION_UNSPECIFIED)
+ .build();
// The activity width is 2100 and the display's app bounds width is 2250, so the activity
// can be aligned inside parentAppBounds
- assertEquals(mActivity.getBounds(), new Rect(175, 0, 2275, 1000));
+ assertEquals(activity.getBounds(), new Rect(175, 0, 2275, 1000));
}
@Test
+ @DisableCompatChanges({ActivityInfo.INSETS_DECOUPLED_CONFIGURATION_ENFORCED})
public void testApplyAspectRatio_activityCannotAlignWithParentAppHorizontal() {
- if (Flags.insetsDecoupledConfiguration()) {
- // TODO (b/151861875): Re-enable it. This is disabled temporarily because the config
- // bounds no longer contains display cutout.
- return;
- }
// The display's app bounds will be (100, 0, 2150, 1000)
final DisplayContent display = new TestDisplayContent.Builder(mAtm, 2300, 1000)
.setCanRotate(false)
@@ -4113,10 +3988,14 @@
.build();
setUpApp(display);
- prepareUnresizable(mActivity, 2.1f /* maxAspect */, SCREEN_ORIENTATION_UNSPECIFIED);
+ final ActivityRecord activity = getActivityBuilderOnSameTask()
+ .setResizeMode(RESIZE_MODE_UNRESIZEABLE)
+ .setMaxAspectRatio(2.1f)
+ .setScreenOrientation(SCREEN_ORIENTATION_UNSPECIFIED)
+ .build();
// The activity width is 2100 and the display's app bounds width is 2050, so the activity
// cannot be aligned inside parentAppBounds and it will fill the parentBounds of the display
- assertEquals(mActivity.getBounds(), display.getBounds());
+ assertEquals(activity.getBounds(), display.getBounds());
}
@Test
@@ -4344,26 +4223,23 @@
@Test
public void testUpdateResolvedBoundsPosition_alignToTop() {
- if (Flags.insetsDecoupledConfiguration()) {
- // TODO (b/151861875): Re-enable it. This is disabled temporarily because the config
- // bounds no longer contains display cutout.
- return;
- }
final int notchHeight = 100;
final DisplayContent display = new TestDisplayContent.Builder(mAtm, 1000, 2800)
.setNotch(notchHeight)
.build();
setUpApp(display);
+ mActivity.mResolveConfigHint.mUseOverrideInsetsForConfig = true;
// Prepare unresizable activity with max aspect ratio
- prepareUnresizable(mActivity, /* maxAspect */ 1.1f, SCREEN_ORIENTATION_UNSPECIFIED);
+ prepareUnresizable(mActivity, 1.1f, SCREEN_ORIENTATION_UNSPECIFIED);
- Rect mBounds = new Rect(mActivity.getWindowConfiguration().getBounds());
+ Rect bounds = new Rect(mActivity.getWindowConfiguration().getBounds());
Rect appBounds = new Rect(mActivity.getWindowConfiguration().getAppBounds());
// The insets should be cut for aspect ratio and then added back because the appBounds
// are aligned to the top of the parentAppBounds
- assertEquals(mBounds, new Rect(0, 0, 1000, 1200));
- assertEquals(appBounds, new Rect(0, notchHeight, 1000, 1200));
+ assertEquals(new Rect(0, notchHeight, 1000, 1200), appBounds);
+ assertEquals(new Rect(0, 0, 1000, 1200), bounds);
+
}
private void assertVerticalPositionForDifferentDisplayConfigsForLandscapeActivity(
@@ -4859,15 +4735,19 @@
*/
private ActivityRecord buildActivityRecord(boolean supportsSizeChanges, int resizeMode,
@ScreenOrientation int screenOrientation) {
- return new ActivityBuilder(mAtm)
- .setTask(mTask)
+ return getActivityBuilderOnSameTask()
.setResizeMode(resizeMode)
.setSupportsSizeChanges(supportsSizeChanges)
.setScreenOrientation(screenOrientation)
+ .build();
+ }
+
+ private ActivityBuilder getActivityBuilderOnSameTask() {
+ return new ActivityBuilder(mAtm)
+ .setTask(mTask)
.setComponent(ComponentName.createRelative(mContext,
SizeCompatTests.class.getName()))
- .setUid(android.os.Process.myUid())
- .build();
+ .setUid(android.os.Process.myUid());
}
static void prepareMinAspectRatio(ActivityRecord activity, float minAspect,
@@ -4931,21 +4811,29 @@
}
}
- /** Asserts that the size of activity is larger than its parent so it is scaling. */
private void assertScaled() {
- assertTrue(mActivity.inSizeCompatMode());
- assertNotEquals(1f, mActivity.getCompatScale(), 0.0001f /* delta */);
+ assertScaled(mActivity);
+ }
+
+ /** Asserts that the size of activity is larger than its parent so it is scaling. */
+ private void assertScaled(ActivityRecord activity) {
+ assertTrue(activity.inSizeCompatMode());
+ assertNotEquals(1f, activity.getCompatScale(), 0.0001f /* delta */);
+ }
+
+ private void assertFitted() {
+ assertFitted(mActivity);
}
/** Asserts that the activity is best fitted in the parent. */
- private void assertFitted() {
- final boolean inSizeCompatMode = mActivity.inSizeCompatMode();
+ private void assertFitted(ActivityRecord activity) {
+ final boolean inSizeCompatMode = activity.inSizeCompatMode();
final String failedConfigInfo = inSizeCompatMode
- ? ("ParentConfig=" + mActivity.getParent().getConfiguration()
- + " ActivityConfig=" + mActivity.getConfiguration())
+ ? ("ParentConfig=" + activity.getParent().getConfiguration()
+ + " ActivityConfig=" + activity.getConfiguration())
: "";
assertFalse(failedConfigInfo, inSizeCompatMode);
- assertFalse(mActivity.hasSizeCompatBounds());
+ assertFalse(activity.hasSizeCompatBounds());
}
/** Asserts the activity max bounds inherit from the TaskDisplayArea. */
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java
index d57a7e6..f94e5e3 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java
@@ -56,6 +56,7 @@
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.mock;
+import android.app.ActivityOptions;
import android.content.pm.SigningDetails;
import android.content.res.Configuration;
import android.graphics.Color;
@@ -291,6 +292,30 @@
}
@Test
+ public void testFindTopNonFinishingActivity_ignoresLaunchedFromBubbleActivities() {
+ final ActivityOptions opts = ActivityOptions.makeBasic();
+ opts.setTaskAlwaysOnTop(true);
+ opts.setLaunchedFromBubble(true);
+ ActivityRecord activity = new ActivityBuilder(mAtm)
+ .setUid(DEFAULT_TASK_FRAGMENT_ORGANIZER_UID).setActivityOptions(opts).build();
+ mTaskFragment.addChild(activity);
+
+ assertNull(mTaskFragment.getTopNonFinishingActivity(true, false));
+ }
+
+ @Test
+ public void testFindTopNonFinishingActivity_includesLaunchedFromBubbleActivities() {
+ final ActivityOptions opts = ActivityOptions.makeBasic();
+ opts.setTaskAlwaysOnTop(true);
+ opts.setLaunchedFromBubble(true);
+ ActivityRecord activity = new ActivityBuilder(mAtm)
+ .setUid(DEFAULT_TASK_FRAGMENT_ORGANIZER_UID).setActivityOptions(opts).build();
+ mTaskFragment.addChild(activity);
+
+ assertEquals(mTaskFragment.getTopNonFinishingActivity(true, true), activity);
+ }
+
+ @Test
public void testMoveTaskToFront_supportsEnterPipOnTaskSwitchForAdjacentTaskFragment() {
final Task bottomTask = createTask(mDisplayContent);
final ActivityRecord bottomActivity = createActivityRecord(bottomTask);
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
old mode 100755
new mode 100644
diff --git a/telecomm/java/android/telecom/InCallAdapter.java b/telecomm/java/android/telecom/InCallAdapter.java
old mode 100755
new mode 100644
diff --git a/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl b/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl
old mode 100755
new mode 100644
diff --git a/telephony/common/com/google/android/mms/package.html b/telephony/common/com/google/android/mms/package.html
old mode 100755
new mode 100644
diff --git a/telephony/common/com/google/android/mms/pdu/PduParser.java b/telephony/common/com/google/android/mms/pdu/PduParser.java
old mode 100755
new mode 100644
diff --git a/telephony/common/com/google/android/mms/pdu/PduPersister.java b/telephony/common/com/google/android/mms/pdu/PduPersister.java
old mode 100755
new mode 100644
diff --git a/telephony/common/com/google/android/mms/pdu/package.html b/telephony/common/com/google/android/mms/pdu/package.html
old mode 100755
new mode 100644
diff --git a/telephony/common/com/google/android/mms/util/package.html b/telephony/common/com/google/android/mms/util/package.html
old mode 100755
new mode 100644
diff --git a/telephony/java/android/telephony/SubscriptionInfo.aidl b/telephony/java/android/telephony/SubscriptionInfo.aidl
old mode 100755
new mode 100644
diff --git a/telephony/java/android/telephony/ims/ImsCallSession.java b/telephony/java/android/telephony/ims/ImsCallSession.java
old mode 100755
new mode 100644
diff --git a/telephony/java/android/telephony/ims/compat/stub/ImsCallSessionImplBase.java b/telephony/java/android/telephony/ims/compat/stub/ImsCallSessionImplBase.java
old mode 100755
new mode 100644
diff --git a/telephony/java/android/telephony/mbms/DownloadRequest.aidl b/telephony/java/android/telephony/mbms/DownloadRequest.aidl
old mode 100755
new mode 100644
diff --git a/telephony/java/android/telephony/mbms/FileInfo.aidl b/telephony/java/android/telephony/mbms/FileInfo.aidl
old mode 100755
new mode 100644
diff --git a/telephony/java/android/telephony/mbms/FileServiceInfo.aidl b/telephony/java/android/telephony/mbms/FileServiceInfo.aidl
old mode 100755
new mode 100644
diff --git a/telephony/java/android/telephony/mbms/IDownloadProgressListener.aidl b/telephony/java/android/telephony/mbms/IDownloadProgressListener.aidl
old mode 100755
new mode 100644
diff --git a/telephony/java/android/telephony/mbms/IDownloadStatusListener.aidl b/telephony/java/android/telephony/mbms/IDownloadStatusListener.aidl
old mode 100755
new mode 100644
diff --git a/telephony/java/android/telephony/mbms/IGroupCallCallback.aidl b/telephony/java/android/telephony/mbms/IGroupCallCallback.aidl
old mode 100755
new mode 100644
diff --git a/telephony/java/android/telephony/mbms/IMbmsDownloadSessionCallback.aidl b/telephony/java/android/telephony/mbms/IMbmsDownloadSessionCallback.aidl
old mode 100755
new mode 100644
diff --git a/telephony/java/android/telephony/mbms/IMbmsGroupCallSessionCallback.aidl b/telephony/java/android/telephony/mbms/IMbmsGroupCallSessionCallback.aidl
old mode 100755
new mode 100644
diff --git a/telephony/java/android/telephony/mbms/IMbmsStreamingSessionCallback.aidl b/telephony/java/android/telephony/mbms/IMbmsStreamingSessionCallback.aidl
old mode 100755
new mode 100644
diff --git a/telephony/java/android/telephony/mbms/IStreamingServiceCallback.aidl b/telephony/java/android/telephony/mbms/IStreamingServiceCallback.aidl
old mode 100755
new mode 100644
diff --git a/telephony/java/android/telephony/mbms/ServiceInfo.aidl b/telephony/java/android/telephony/mbms/ServiceInfo.aidl
old mode 100755
new mode 100644
diff --git a/telephony/java/android/telephony/mbms/StreamingServiceInfo.aidl b/telephony/java/android/telephony/mbms/StreamingServiceInfo.aidl
old mode 100755
new mode 100644
diff --git a/telephony/java/android/telephony/mbms/UriPathPair.aidl b/telephony/java/android/telephony/mbms/UriPathPair.aidl
old mode 100755
new mode 100644
diff --git a/telephony/java/android/telephony/mbms/vendor/IMbmsDownloadService.aidl b/telephony/java/android/telephony/mbms/vendor/IMbmsDownloadService.aidl
old mode 100755
new mode 100644
diff --git a/telephony/java/android/telephony/mbms/vendor/IMbmsGroupCallService.aidl b/telephony/java/android/telephony/mbms/vendor/IMbmsGroupCallService.aidl
old mode 100755
new mode 100644
diff --git a/telephony/java/android/telephony/mbms/vendor/IMbmsStreamingService.aidl b/telephony/java/android/telephony/mbms/vendor/IMbmsStreamingService.aidl
old mode 100755
new mode 100644
diff --git a/telephony/java/com/android/internal/telephony/IOns.aidl b/telephony/java/com/android/internal/telephony/IOns.aidl
old mode 100755
new mode 100644
diff --git a/telephony/java/com/android/internal/telephony/PhoneConstants.java b/telephony/java/com/android/internal/telephony/PhoneConstants.java
index a9ebd5c..2158f3d 100644
--- a/telephony/java/com/android/internal/telephony/PhoneConstants.java
+++ b/telephony/java/com/android/internal/telephony/PhoneConstants.java
@@ -252,4 +252,10 @@
/** The key to specify the emergency service category */
public static final String EXTRA_EMERGENCY_SERVICE_CATEGORY = "emergency_service_category";
+
+ /** The key to specify the alternate emergency URNs */
+ public static final String EXTRA_EMERGENCY_URNS = "emergency_urns";
+
+ /** The key to specify whether or not to use emergency routing */
+ public static final String EXTRA_USE_EMERGENCY_ROUTING = "use_emergency_routing";
}
diff --git a/test-mock/api/system-current.txt b/test-mock/api/system-current.txt
index f350957..7d891c8 100644
--- a/test-mock/api/system-current.txt
+++ b/test-mock/api/system-current.txt
@@ -28,7 +28,7 @@
method @Deprecated public void removeOnPermissionsChangeListener(android.content.pm.PackageManager.OnPermissionsChangedListener);
method @Deprecated public void revokeRuntimePermission(String, String, android.os.UserHandle);
method @Deprecated public boolean setDefaultBrowserPackageNameAsUser(String, int);
- method public String[] setPackagesSuspended(String[], boolean, android.os.PersistableBundle, android.os.PersistableBundle, String);
+ method @Deprecated public String[] setPackagesSuspended(String[], boolean, android.os.PersistableBundle, android.os.PersistableBundle, String);
method @Deprecated public void setUpdateAvailable(String, boolean);
method @Deprecated public boolean updateIntentVerificationStatusAsUser(String, int, int);
method @Deprecated public void updatePermissionFlags(String, String, int, int, android.os.UserHandle);
diff --git a/tests/AccessoryDisplay/sink/res/drawable-hdpi/ic_app.png b/tests/AccessoryDisplay/sink/res/drawable-hdpi/ic_app.png
old mode 100755
new mode 100644
Binary files differ
diff --git a/tests/AccessoryDisplay/source/res/drawable-hdpi/ic_app.png b/tests/AccessoryDisplay/source/res/drawable-hdpi/ic_app.png
old mode 100755
new mode 100644
Binary files differ
diff --git a/tests/AttestationVerificationTest/AndroidManifest.xml b/tests/AttestationVerificationTest/AndroidManifest.xml
old mode 100755
new mode 100644
diff --git a/tests/DozeTest/res/drawable-hdpi/ic_app.png b/tests/DozeTest/res/drawable-hdpi/ic_app.png
old mode 100755
new mode 100644
Binary files differ
diff --git a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/splitscreen/EnterSystemSplitTest.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/splitscreen/EnterSystemSplitTest.kt
index a23f211..379b45c 100644
--- a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/splitscreen/EnterSystemSplitTest.kt
+++ b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/splitscreen/EnterSystemSplitTest.kt
@@ -24,7 +24,6 @@
import android.tools.flicker.legacy.LegacyFlickerTest
import android.tools.flicker.legacy.LegacyFlickerTestFactory
import android.tools.traces.parsers.toFlickerComponent
-import androidx.test.filters.FlakyTest
import com.android.server.wm.flicker.activityembedding.ActivityEmbeddingTestBase
import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper
import com.android.server.wm.flicker.testapp.ActivityOptions
@@ -175,12 +174,6 @@
}
}
- @FlakyTest(bugId = 342596801)
- @Test
- override fun visibleWindowsShownMoreThanOneConsecutiveEntry() {
- super.visibleWindowsShownMoreThanOneConsecutiveEntry()
- }
-
@Ignore("Not applicable to this CUJ.")
override fun visibleLayersShownMoreThanOneConsecutiveEntry() {}
diff --git a/tests/Internal/TEST_MAPPING b/tests/Internal/TEST_MAPPING
new file mode 100644
index 0000000..20af028
--- /dev/null
+++ b/tests/Internal/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "postsubmit": [
+ {
+ "name": "InternalTests"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/tests/OdmApps/app/AndroidManifest.xml b/tests/OdmApps/app/AndroidManifest.xml
old mode 100755
new mode 100644
diff --git a/tests/OdmApps/priv-app/AndroidManifest.xml b/tests/OdmApps/priv-app/AndroidManifest.xml
old mode 100755
new mode 100644
diff --git a/tests/RemoteDisplayProvider/res/drawable-hdpi/ic_app.png b/tests/RemoteDisplayProvider/res/drawable-hdpi/ic_app.png
old mode 100755
new mode 100644
Binary files differ
diff --git a/tests/inputmethod/ConcurrentMultiSessionImeTest/src/com/android/server/inputmethod/multisessiontest/ConcurrentMultiUserTest.java b/tests/inputmethod/ConcurrentMultiSessionImeTest/src/com/android/server/inputmethod/multisessiontest/ConcurrentMultiUserTest.java
index 56dbde0..fff1dd1 100644
--- a/tests/inputmethod/ConcurrentMultiSessionImeTest/src/com/android/server/inputmethod/multisessiontest/ConcurrentMultiUserTest.java
+++ b/tests/inputmethod/ConcurrentMultiSessionImeTest/src/com/android/server/inputmethod/multisessiontest/ConcurrentMultiUserTest.java
@@ -39,11 +39,13 @@
import org.junit.After;
import org.junit.Before;
import org.junit.ClassRule;
+import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(BedsteadJUnit4.class)
+@Ignore("b/345557347")
public final class ConcurrentMultiUserTest {
@ClassRule
diff --git a/tools/codegen/src/com/android/codegen/Main.kt b/tools/codegen/src/com/android/codegen/Main.kt
old mode 100755
new mode 100644
diff --git a/tools/localedata/extract_icu_data.py b/tools/localedata/extract_icu_data.py
index 81ac897..8f67fa8 100755
--- a/tools/localedata/extract_icu_data.py
+++ b/tools/localedata/extract_icu_data.py
@@ -22,6 +22,8 @@
import os.path
import sys
+import xml.etree.ElementTree as ElementTree
+
def get_locale_parts(locale):
"""Split a locale into three parts, for langauge, script, and region."""
@@ -40,42 +42,43 @@
def read_likely_subtags(input_file_name):
"""Read and parse ICU's likelySubtags.txt."""
- with open(input_file_name) as input_file:
- likely_script_dict = {
- # Android's additions for pseudo-locales. These internal codes make
- # sure that the pseudo-locales would not match other English or
- # Arabic locales. (We can't use private-use ISO 15924 codes, since
- # they may be used by apps for other purposes.)
- "en_XA": "~~~A",
- "ar_XB": "~~~B",
- # Removed data from later versions of ICU
- "ji": "Hebr", # Old code for Yiddish, still used in Java and Android
- }
- representative_locales = {
- # Android's additions
- "en_Latn_GB", # representative for en_Latn_001
- "es_Latn_MX", # representative for es_Latn_419
- "es_Latn_US", # representative for es_Latn_419 (not the best idea,
- # but Android has been shipping with it for quite a
- # while. Fortunately, MX < US, so if both exist, MX
- # would be chosen.)
- }
- for line in input_file:
- line = line.strip(u' \n\uFEFF')
- if line.startswith('//'):
- continue
- if '{' in line and '}' in line:
- from_locale = line[:line.index('{')]
- to_locale = line[line.index('"')+1:line.rindex('"')]
- from_lang, from_scr, from_region = get_locale_parts(from_locale)
- _, to_scr, to_region = get_locale_parts(to_locale)
- if from_lang == 'und':
- continue # not very useful for our purposes
- if from_region is None and to_region not in ['001', 'ZZ']:
- representative_locales.add(to_locale)
- if from_scr is None:
- likely_script_dict[from_locale] = to_scr
- return likely_script_dict, frozenset(representative_locales)
+ likely_script_dict = {
+ # Android's additions for pseudo-locales. These internal codes make
+ # sure that the pseudo-locales would not match other English or
+ # Arabic locales. (We can't use private-use ISO 15924 codes, since
+ # they may be used by apps for other purposes.)
+ "en_XA": "~~~A",
+ "ar_XB": "~~~B",
+ # Removed data from later versions of ICU
+ "ji": "Hebr", # Old code for Yiddish, still used in Java and Android
+ }
+ representative_locales = {
+ # Android's additions
+ "en_Latn_GB", # representative for en_Latn_001
+ "es_Latn_MX", # representative for es_Latn_419
+ "es_Latn_US", # representative for es_Latn_419 (not the best idea,
+ # but Android has been shipping with it for quite a
+ # while. Fortunately, MX < US, so if both exist, MX
+ # would be chosen.)
+ }
+ xml_tree = ElementTree.parse(input_file_name)
+ likely_subtags = xml_tree.find('likelySubtags')
+ for child in likely_subtags:
+ from_locale = child.get('from')
+ to_locale = child.get('to')
+ # print(f'from: {from_locale} to: {to_locale}')
+ from_lang, from_scr, from_region = get_locale_parts(from_locale)
+ _, to_scr, to_region = get_locale_parts(to_locale)
+ if to_locale == "FAIL":
+ continue # "FAIL" cases are not useful here.
+ if from_lang == 'und':
+ continue # not very useful for our purposes
+ if from_region is None and to_region not in ['001', 'ZZ']:
+ representative_locales.add(to_locale)
+ if from_scr is None:
+ likely_script_dict[from_locale] = to_scr
+
+ return likely_script_dict, frozenset(representative_locales)
# From packLanguageOrRegion() in ResourceTypes.cpp
@@ -86,7 +89,7 @@
elif len(inp) == 2:
return ord(inp[0]), ord(inp[1])
else:
- assert len(inp) == 3
+ assert len(inp) == 3, f'Expects a 3-character string, but "{inp}" '
base = ord(base)
first = ord(inp[0]) - base
second = ord(inp[1]) - base
@@ -161,9 +164,10 @@
print('});')
-def read_and_dump_likely_data(icu_data_dir):
+def read_and_dump_likely_data(cldr_source_dir):
"""Read and dump the likely-script data."""
- likely_subtags_txt = os.path.join(icu_data_dir, 'misc', 'likelySubtags.txt')
+ likely_subtags_txt = os.path.join(cldr_source_dir,
+ 'common', 'supplemental', 'likelySubtags.xml')
likely_script_dict, representative_locales = read_likely_subtags(
likely_subtags_txt)
@@ -280,10 +284,11 @@
icu_data_dir = os.path.join(
source_root,
'external', 'icu', 'icu4c', 'source', 'data')
+ cldr_source_dir = os.path.join(source_root, 'external', 'cldr')
print('// Auto-generated by %s' % sys.argv[0])
print()
- likely_script_dict = read_and_dump_likely_data(icu_data_dir)
+ likely_script_dict = read_and_dump_likely_data(cldr_source_dir)
read_and_dump_parent_data(icu_data_dir, likely_script_dict)
diff --git a/wifi/java/src/android/net/wifi/SoftApConfToXmlMigrationUtil.java b/wifi/java/src/android/net/wifi/SoftApConfToXmlMigrationUtil.java
old mode 100755
new mode 100644
diff --git a/wifi/java/src/android/net/wifi/WifiMigration.java b/wifi/java/src/android/net/wifi/WifiMigration.java
old mode 100755
new mode 100644
diff --git a/wifi/java/src/android/net/wifi/WifiNetworkScoreCache.java b/wifi/java/src/android/net/wifi/WifiNetworkScoreCache.java
old mode 100755
new mode 100644